Entity Framework . 基本操作 (ObjectContext & EntityObject)

1. ObjectContext 

ObjectContext 对应 LINQ to SQL 的 DataContext,我们通过它来管理数据库连接、实体对象查询更新等。

public class ObjectContext : IDisposable
{
    // Events
public event EventHandler SavingChanges;
// Methods
public ObjectContext(EntityConnection connection);
public ObjectContext(string connectionString);
private ObjectContext(EntityConnection connection, bool isConnectionConstructor);
protected ObjectContext(EntityConnection connection, string defaultContainerName);
protected ObjectContext(string connectionString, string defaultContainerName);
public void AcceptAllChanges();
public void AddObject(string entitySetName, object entity);
public void ApplyPropertyChanges(string entitySetName, object changed);
public void Attach(IEntityWithKey entity);
public void AttachTo(string entitySetName, object entity);
public EntityKey CreateEntityKey(string entitySetName, object entity);
public ObjectQuery<T> CreateQuery<T>(string queryString, params ObjectParameter[] parameters);
public void DeleteObject(object entity);
public void Detach(object entity);
public void Dispose();
public object GetObjectByKey(EntityKey key);
public void Refresh(RefreshMode refreshMode, IEnumerable collection);
public void Refresh(RefreshMode refreshMode, object entity);
public int SaveChanges();
public int SaveChanges(bool acceptChangesDuringSave);
public bool TryGetObjectByKey(EntityKey key, out object value);
// Properties
public int? CommandTimeout { get; set; }
public DbConnection Connection { get; }
public string DefaultContainerName { get; set; }
public MetadataWorkspace MetadataWorkspace { get; }
public ObjectStateManager ObjectStateManager { get; }
}
public partial class TestEntities : ObjectContext
{ public ObjectQuery<User> User
{
get
{
if ((this._User == null))
{
this._User = base.CreateQuery<User>("[User]");
}
return this._User;
}
}
private ObjectQuery<User> _User;
public void AddToUser(User user)
{ base.AddObject("User", user);
} }


使用演示

using (var context = new TestEntities())
{
    context.Connection.StateChange += (s, e) => Console.WriteLine("{0} -> {1}", e.OriginalState, e.CurrentState);
    context.Connection.Disposed += (s, e) => Console.WriteLine("Dispose...");
    context.Connection.Open();
}


2. EntityObject 

EF 总算是补齐了序列化特性,省得我们自己去折腾了。

[EdmEntityType(NamespaceName = "TestModel", Name = "User")]
[DataContract(IsReference = true)]
[Serializable()]
public partial class User : EntityObject
{
public static User CreateUser(int id, string name)
{
User user = new User();
user.Id = id;
user.Name = name;
return user;
}

[EdmScalarProperty(EntityKeyProperty = true, IsNullable = false)]
[DataMember]
public int Id
{
get
{
return this._Id;
}
set
{
this.OnIdChanging(value);
this.ReportPropertyChanging("Id");
this._Id = StructuralObject.SetValidValue(value);
this.ReportPropertyChanged("Id");
this.OnIdChanged();
}
}
private int _Id;
partial void OnIdChanging(int value);
partial void OnIdChanged();
[EdmScalarProperty(IsNullable = false)]
[DataMember]
public string Name
{
get
{
return this._Name;
}
set
{
this.OnNameChanging(value);
this.ReportPropertyChanging("Name");
this._Name = StructuralObject.SetValidValue(value, false);
this.ReportPropertyChanged("Name");
this.OnNameChanged();
}
}
private string _Name;
partial void OnNameChanging(string value);
partial void OnNameChanged();
[EdmRelationshipNavigationProperty("TestModel", "FK_Order_User", "Order")]
[XmlIgnore]
[SoapIgnore]
[DataMember]
public EntityCollection<Order> Order
{
get
{
return ((IEntityWithRelationships)(this)).RelationshipManager.
GetRelatedCollection<Order>("TestModel.FK_Order_User", "Order");
}
set
{
if ((value != null))
{
((IEntityWithRelationships)(this)).RelationshipManager.
InitializeRelatedCollection<Order>("TestModel.FK_Order_User", "Order", value);
}
}
}
}


3. LINQ to Entities 

这个最易上手,基本上和 LINQ to SQL 没啥区别。

using (var context = new TestEntities())
{
    var user = (from u in context.User where u.Name == "user1" select u).FirstOrDefault();
    Console.WriteLine(user.Name);
    var users = from u in context.User where u.Age > 0 select new { u.Id, u.Name };
    foreach (var item in users)
    {
        Console.WriteLine(item.Name);
    }
}


4. Entity SQL 

这是很多 LINQ to SQL 用户所期望的,一种类似 T-SQL 且面向对象查询语言。

using (var context = new TestEntities())
{
    var sql = "SELECT VALUE u FROM TestEntities.User AS u WHERE u.Name = @name";
    var user = context.CreateQuery<User>(sql, new ObjectParameter("name", "user1"));
    foreach (var item in user)
{ Console.WriteLine(item.Name); } }


这种参数化的查询方式有点像我们熟悉的 DbParameter。

我们也可以查询某几个属性值,但返回 的不是匿名类型,而是 System.Data.Common.DbDataRecord。

using (var context = new TestEntities())
{
    var sql = "SELECT u.Id, u.Name FROM TestEntities.User AS u WHERE u.Name = @name";
    var reader = context.CreateQuery<DbDataRecord>(sql, new ObjectParameter("name", "user1"));
    foreach (var item in reader)
    {
        Console.WriteLine(item["name"]);
    }
}


如果只是返回单个属性,别忘了 "VALUE" 。

var sql = "SELECT VALUE u.Name FROM TestEntities.User AS u WHERE u.Name = @name";
var reader = context.CreateQuery<string>(sql, new ObjectParameter("name", "user1"));
foreach (var item in reader)
{
    Console.WriteLine(item);
}

5. Method-Based Syntax 

用相关方法实现 Chaining Queries,分为 LINQ Method-Based Queries 和 ObjectQuery's Query Builder Methods 两种。

using (var context = new TestEntities())
{
    var user = context.User.Where(u => u.Name == "user1").Select(u => new { u.Id, u.Name }).First();
    Console.WriteLine(user.Name);
    // ---------------------
    var users = context.User. Where("it.Name = @name", new ObjectParameter("name", "user1")).Select("it.Name, it.Age").Top("@num", new ObjectParameter("num", 2));
    foreach (var item in users)
    {
        Console.WriteLine(item["name"]);
    }
}


ObjectQuery<T> 提供了这些基于 Entity SQL 字符串的查询方式。

public class ObjectQuery<T> : ObjectQuery, ...
{
    public ObjectQuery<DbDataRecord> GroupBy(string keys, string projection, params ...);
public ObjectQuery<T> Include(string path);
public ObjectQuery<T> Intersect(ObjectQuery<T> query);
public ObjectQuery<TResultType> OfType<TResultType>();
public ObjectQuery<T> OrderBy(string keys, params ObjectParameter[] parameters);
public ObjectQuery<DbDataRecord> Select(string projection, params ObjectParameter[] parameters);
public ObjectQuery<TResultType> SelectValue<TResultType>(string projection, params ...);
public ObjectQuery<T> Skip(string keys, string count, params ObjectParameter[] parameters);
IEnumerator<T> IEnumerable<T>.GetEnumerator();
public ObjectQuery<T> Top(string count, params ObjectParameter[] parameters);
public ObjectQuery<T> Union(ObjectQuery<T> query);
public ObjectQuery<T> UnionAll(ObjectQuery<T> query);
public ObjectQuery<T> Where(string predicate, params ObjectParameter[] parameters); private string _name; private const string DefaultName = "it"; public string Name { get; set; } }

6. EntityClient 

这种方式非常类似传统 ADO.NET 操作。

using (var conn = new EntityConnection("name=TestEntities"))
{
    conn.Open();
    var cmd = conn.CreateCommand();
    cmd.CommandText = "SELECT VALUE u FROM TestEntities.User AS u WHERE u.Name == @name";
    cmd.Parameters.Add(new EntityParameter { ParameterName = "name", Value = "user1" });
    using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
    {
        while (reader.Read())
        {
            Console.WriteLine(reader["Name"]);
        }
    }
}


7. Add 

注意 ObjectContext 用 ObjectQuery<T> 返回 EntitySet,添加实体对象实际通过 ObjectContext.AddObject() 完成的。

using (var context = new TestEntities())
{
    var user = new User { Name = "user3", Age = 23 };
    context.AddToUser(user);
    context.SaveChanges();
}


8. Update

using (var context = new TestEntities())
{
    var user = context.User.Where(u => u.Name == "user1").FirstOrDefault();
    user.Age += 2;
    context.SaveChanges();
}


9. Delete

using (var context = new TestEntities())
{
    var user = context.User.Where(u => u.Name == "user2").FirstOrDefault();
context.DeleteObject(user); context.SaveChanges(); }


10. Refresh 

ObjectContext.Refresh() 允许我们自行决定刷新策略,包括数据库优先或者本地修改优先。

using (var context = new TestEntities())
{
    var user = context.User.Where(u => u.Name == "user1").FirstOrDefault();
    user.Age += 13;
    var age = user.Age;
    context.Refresh(RefreshMode.StoreWins, user);
    Console.WriteLine("{0}, {1}", user.Age, age);
}


11. ToTraceString 

ObjectContext 并没有提供 LINQ to SQL DataContext.Log 这样的功能,要查看实际生成的 T-SQL 语句,要么借助 SQL Server Sql Profiler 这样的工具,要么使用 ObjectQuery.ToTraceString() 方法。

using (var context = new TestEntities())

{
    var users1 = context.User.Where(u => u.Name == "user1");
    Console.WriteLine((users1 as ObjectQuery).ToTraceString());
var users2 = from u in context.User where u.Name == "user1" select u; Console.WriteLine((users2 as ObjectQuery).ToTraceString());

var sql = "SELECT VALUE u FROM TestEntities.User AS u WHERE u.Name = 'user1'"; var users3 = context.CreateQuery<User>(sql); Console.WriteLine(users3.ToTraceString()) }

输出:

SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[Age] AS [Age]
FROM [dbo].[User] AS [Extent1]
WHERE N'user1' = [Extent1].[Name]
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[Age] AS [Age]
FROM [dbo].[User] AS [Extent1]
WHERE N'user1' = [Extent1].[Name]
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[Age] AS [Age]
FROM [dbo].[User] AS [Extent1]
WHERE [Extent1].[Name] = 'user1'


12. Connection.Open 

当 执行多个操作时,Context 默认情况下会多次打开和关闭数据库连接,可能会造成一定的性能问题。

using (var context = new TestEntities())
{ context.Connection.StateChange += (s, e) => Console.WriteLine("{0} -> {1}", e.OriginalState, e.CurrentState); context.Connection.Disposed += (s, e) => Console.WriteLine("Dispose..."); var user = context.User.First(); Console.WriteLine(user.Age); var order = context.Order.First(); Console.WriteLine(order.Id); }


输出:

Closed -> Open
Open -> Closed
23
Closed -> Open
Open -> Closed
1
Dispose...

我们可以显示打开数据库连接来避免这样的状况。

using (var context = new TestEntities())
{
    context.Connection.StateChange += (s, e) => Console.WriteLine("{0} -> {1}", e.OriginalState, e.CurrentState);
    context.Connection.Disposed += (s, e) => Console.WriteLine("Dispose...");
    context.Connection.Open();
    var user = context.User.First();
    Console.WriteLine(user.Age);
    var order = context.Order.First();
    Console.WriteLine(order.Id);
}


输出:

Closed -> Open
23
1
Open -> Closed
Dispose...

13. ExecuteCommand 

ObjectContext 并没有提供 ExecuteCommand 之类执行原生 T-SQL 的方法,虽然可以用存储过程映射来解决,但总归是少了些什么。某些时候可能因为性能等原因,需要执行一些特殊的操作,那么下面的代码可能帮上一些忙。

using (var context = new TestEntities())
{
    var bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
    var factoryProperty = typeof(EntityConnection).GetProperty("StoreProviderFactory", bindingFlags);
    var factory = factoryProperty.GetValue(context.Connection, null) as DbProviderFactory;
    var connStr = (context.Connection as EntityConnection).StoreConnection.ConnectionString;
    using (var conn = factory.CreateConnection())
    {
        conn.ConnectionString = connStr;
        conn.Open();
        var cmd = factory.CreateCommand();
        cmd.Connection = conn;
        cmd.CommandText = "select count(*) from [user]";
        Console.WriteLine(cmd.ExecuteScalar());
    }
}
原文地址:https://www.cnblogs.com/wang726zq/p/2441365.html