C# 使用实体框架添加和更新实体
在我的上一个项目中,我首先使用了EntityFramework5代码。我完成了我的项目,但在开发过程中经历了很多痛苦 我试图在下面解释我的痛苦: 我的数据访问逻辑层中有几个数据类,如产品、产品类别、订单、公司、制造商等。。。每个类都有一些对其他类的引用。例如,产品实例具有ProductCategory属性 在我的数据访问对象类的Add和Update方法中,我在上下文中将每个属性(基本类型除外)的状态设置为Unchanged或Modified。下面是某个dao类的更新方法的某些部分:C# 使用实体框架添加和更新实体,c#,entity-framework-5,dao,C#,Entity Framework 5,Dao,在我的上一个项目中,我首先使用了EntityFramework5代码。我完成了我的项目,但在开发过程中经历了很多痛苦 我试图在下面解释我的痛苦: 我的数据访问逻辑层中有几个数据类,如产品、产品类别、订单、公司、制造商等。。。每个类都有一些对其他类的引用。例如,产品实例具有ProductCategory属性 在我的数据访问对象类的Add和Update方法中,我在上下文中将每个属性(基本类型除外)的状态设置为Unchanged或Modified。下面是某个dao类的更新方法的某些部分: contex
context.Entry(entity).State = System.Data.EntityState.Modified;
if (entity.Category != null)
context.Entry(entity.Category).State = System.Data.EntityState.Unchanged;
if (entity.Manufacturer != null)
context.Entry(entity.Manufacturer).State = System.Data.EntityState.Unchanged;
foreach (var specificationDefinition in entity.SpecificationDefinitions)
{
context.Entry(specificationDefinition).State = System.Data.EntityState.Unchanged;
foreach (var specificationValue in specificationDefinition.Values)
{
context.Entry(specificationValue).State = System.Data.EntityState.Unchanged;
}
}
这个代码是这样的。我的一些add或update方法大约有30行代码。我认为我做错了什么,添加或更新一个实体应该不会这么痛苦,但是当我没有设置对象的状态时,我会在数据库中得到异常或重复条目。我真的必须设置映射到数据库的每个属性的状态吗?好的,那么您只是做错了什么。 除了我的评论之外,我还为您创建了一个示例,显示EF默认情况下不会创建重复项 我有两门课:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public ProductCategory Category { get; set; }
public decimal Price { get; set; }
}
public class ProductCategory
{
public int Id { get; set; }
public string Name { get; set; }
}
一个背景:
public class MyContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<ProductCategory> ProductCategories { get; set; }
public MyContext()
: base("name=MyContext")
{
}
public MyContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<MyContext>(null);
// Table mappings
modelBuilder.Entity<Product>().ToTable("Product");
modelBuilder.Entity<ProductCategory>().ToTable("ProductCategory");
base.OnModelCreating(modelBuilder);
}
}
此外,在SQLServerManagementStudio中查看时,此解决方案仅创建(并更新)了一个产品和一个类别
当然,您应该使用存储库来检索、更新和删除您的数据和工作单元。这些都被排除在示例之外
因此,如果您不发布任何代码,我们将无法为您提供更多帮助:-)您可以用以下代码替换您的代码:
context.Products.Attach(entity);
context.Entry(entity).State = System.Data.EntityState.Modified;
这是相同的原因(除非相关实体已附加到另一个状态的上下文,而不是以前的
未更改
),因为附加
将对象图中包含所有相关实体的实体
放入状态未更改
的上下文中。将实体
的状态设置为修改
之后,仅会将产品(而非相关实体)的状态从未更改
更改为修改
是否可以添加用于创建数据的代码?如果类中的引用正确,EF应该只创建一次所有实例。是的,它一次创建所有实例。事实上,这就是问题所在。让我再解释一下这个问题。假设我有一个Product实例,其中包含一个ProductType实例。假设产品实例已在过去持久化。当我尝试更新该产品实例时,如果我不将ProductType属性的状态设置为Unchanged,EF将创建一个重复的ProductType实例(我不希望出现这种情况)。如果从另一个(尚未处理的)上下文检索实体,这将不起作用。你会得到一个例外。@MichaelLogutov:你是对的,但我几乎可以肯定问题中的场景是一个分离的场景(即,先前的上下文已经被释放)。否则无论如何都会容易得多,因为您通常根本不需要摆弄任何实体状态,因为更改跟踪将自动跟踪正确的状态。
static void Main(string[] args)
{
var prodCat = new ProductCategory()
{
Name = "Category 1"
};
var prod = new Product()
{
Name = "Product 1",
Category = prodCat,
Price = 19.95M
};
using (var context = new MyContext())
{
var initializer = new InitDb<MyContext>();
initializer.InitializeDatabase(context);
Console.WriteLine("Adding products and categories to context.");
context.ProductCategories.Add(prodCat);
context.Products.Add(prod);
Console.WriteLine();
Console.WriteLine("Saving initial context.");
context.SaveChanges();
Console.WriteLine("Context saved.");
Console.WriteLine();
Console.WriteLine("Changing product details.");
var initProd = context.Products.Include(x => x.Category).SingleOrDefault(x => x.Id == 1);
PrintProduct(initProd);
initProd.Name = "Product 1 modified";
initProd.Price = 29.95M;
initProd.Category.Name = "Category 1 modified";
PrintProduct(initProd);
Console.WriteLine();
Console.WriteLine("Saving modified context.");
context.SaveChanges();
Console.WriteLine("Context saved.");
Console.WriteLine();
Console.WriteLine("Getting modified product from database.");
var modProd = context.Products.Include(x => x.Category).SingleOrDefault(x => x.Id == 1);
PrintProduct(modProd);
Console.WriteLine();
Console.WriteLine("Finished!");
Console.ReadKey();
}
}
static void PrintProduct(Product prod)
{
Console.WriteLine(new string('-', 10));
Console.WriteLine("Id : {0}", prod.Id);
Console.WriteLine("Name : {0}", prod.Name);
Console.WriteLine("Price : {0}", prod.Price);
Console.WriteLine("CatId : {0}", prod.Category.Id);
Console.WriteLine("CatName : {0}", prod.Category.Name);
Console.WriteLine(new string('-', 10));
}
Adding products and categories to context.
Saving initial context.
Context saved.
Changing product details.
----------
Id : 1
Name : Product 1
Price : 19,95
CatId : 1
CatName : Category 1
----------
----------
Id : 1
Name : Product 1 modified
Price : 29,95
CatId : 1
CatName : Category 1 modified
----------
Saving modified context.
Context saved.
Getting modified product from database.
----------
Id : 1
Name : Product 1 modified
Price : 29,95
CatId : 1
CatName : Category 1 modified
----------
Finished!
context.Products.Attach(entity);
context.Entry(entity).State = System.Data.EntityState.Modified;