我想删除在两个实体上拆分的表格行。
如果我尝试删除主要实体,如果在我未使用context.Entry(...).Reference
加载相关的其他实体之前,我会收到错误。
在我要删除整行之前检索相关实体有点傻吗?
如果我继续评论context.Entry(...)
行
遇到无效数据。缺少必需的关系。检查 State Entries确定约束违规的来源。
我添加以下代码。可以请某人帮我删除拆分实体,而不必在之前“加载”相关实体吗?
using System.Data.Entity;
using System.Linq;
namespace Split
{
class Program
{
static void Main(string[] args)
{
using (var context = new DataContext())
{
var product = new Product()
{
Name = "my Article",
Photo = new ProductPhoto() { PhotoUrl = "http://myfoto.jpg" }
};
context.Products.Add(product);
context.SaveChanges();
}
using (var context = new DataContext())
{
var product = context.Products.First();
//context.Entry(product).Reference(e => e.Photo).Load();
context.Products.Remove(product);
context.SaveChanges();
}
}
}
class Product
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual ProductPhoto Photo { get; set; }
}
class ProductPhoto
{
public virtual int ProductId { get; set; }
public virtual string PhotoUrl { get; set; }
public virtual Product Product { get; set; }
}
class DataContext : DbContext
{
public DataContext()
: base("name=DefaultConnection")
{
Configuration.ProxyCreationEnabled = false;
Configuration.LazyLoadingEnabled = false;
}
public DbSet<Product> Products { get; set; }
public DbSet<ProductPhoto> ProductPhotos { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.ToTable("Products")
.HasKey(e => e.Id)
.HasRequired(e => e.Photo)
.WithRequiredPrincipal(e => e.Product);
modelBuilder.Entity<ProductPhoto>()
.ToTable("Products")
.HasKey(e => e.ProductId);
base.OnModelCreating(modelBuilder);
}
}
}
答案 0 :(得分:4)
执行此操作的最佳方法是使用存根实体:实体对象只能获得Id值:
var product = context.Products.First();
var photo = new ProductPhoto { ProductId = product.ProductId }; // Stub
context.Entry(photo).State = System.Data.Entity.EntityState.Deleted;
context.Products.Remove(product);
context.SaveChanges();
如果您知道Product
的ID,您甚至可以通过仅创建两个存根来删除Product
及其ProductPhoto
。
答案 1 :(得分:0)
可能会像这样加载产品:
var product = context.Products.Include(x => x.Photo).First();
保存一行,但仍会从数据库加载照片。
答案 2 :(得分:0)
尝试将级联删除规则添加到模型中。您必须在数据库中有相应的DELETE规则,以避免将依赖项加载到内存中as noted here.
答案 3 :(得分:0)
Gert Arnold建议的解决方案就是内存 存根一个用于实体,另一个用于相关的子实体 我粘贴了一个新的代码(见评论)
我发布了Gert Arnold提出的想法的解决方案,也许代码可以优化,我试图尽可能多地使用它。
如果您的实体包含任何并发令牌,那么这些属性也是 用于构造DELETE语句。您仍然可以使用存根实体 方法,但您需要为并发令牌设置值 属性也是如此。
引自:“编程实体框架:DbContext 由Julia Lerman和Rowan Miller(O'Reilly)。版权所有2012 Julia Lerman和 Rowan Miller,978-1-449-31296-1。“
using System;
using System.Data.Entity;
using System.Linq;
using System.Reflection;
namespace Split
{
class Program
{
static void Main()
{
Database.SetInitializer(new DropCreateDatabaseAlways<DataContext>());
const int id = 1;
const string split = "Info"; // contract: if the entity being delete has an Info property then the row has been splitted
using (var context = new DataContext()) // Add
{
var product = new Product
{
Name = "my Article 1",
Info = new ProductInfo { PhotoUrl = "http://myphoto.jpg" } // when adding an entity the subEntity MUST BE included on the graph
};
context.Products.Add(product);
context.SaveChanges();
}
using (var context = new DataContext())
{
var product = context.Products.Find(id);
context.Entry(product).Reference(e => e.Info).Load(); // when adding an entity the subEntity COULD BE OR NOT included on the graph, no need to include it if we are not going to modify it
product.Name = "MY ARTICULE 1";
product.Info.PhotoUrl = "HTTP://MYPHOTO.JPG";
context.Entry(product).State = EntityState.Modified;
context.SaveChanges();
}
using (var context = new DataContext())
{
PropertyInfo propertyInfo;
context.Products.Find(id); // uncoment bring it to memory and test with entity in memory
var entity = context.Products.Local.FirstOrDefault(e => e.Id == id);
context.Entry(entity).Reference(e => e.Info).Load();
if (entity != null) // there is a entity already yet in memory
{
propertyInfo = entity.GetType().GetProperty(split); // contract
if (propertyInfo != null)
{
var subEntity = propertyInfo.GetValue(entity); // get subEntity from entity Info property
context.Entry(subEntity).State = EntityState.Detached; // remove sub entity from ChangeTracker API
propertyInfo.SetValue(entity, null); // remove subEntity and relationship
}
context.Entry(entity).State = EntityState.Detached; // remove entity from ChangeTracker API
}
entity = new Product { Id = id }; // new entity stub
propertyInfo = entity.GetType().GetProperty(split); // contract:
if (propertyInfo != null)
{
propertyInfo.SetValue(entity, null); // remove subEntity and and relationship
var subEntity = Activator.CreateInstance(propertyInfo.PropertyType); // create a new subEntity stub
subEntity.GetType().GetProperty("Id").SetValue(subEntity, id); // set the foreinkey relation
context.Entry(subEntity).State = EntityState.Deleted; // mark as deleted on context
}
context.Entry(entity).State = EntityState.Deleted; // delete the entity
context.SaveChanges();
}
}
}
class Product
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual ProductInfo Info { get; set; }
}
class ProductInfo
{
public virtual int Id { get; set; }
public virtual string PhotoUrl { get; set; }
public virtual Product Product { get; set; }
}
class DataContext : DbContext
{
public DataContext()
: base("name=DefaultConnection")
{
Configuration.ProxyCreationEnabled = false;
Configuration.LazyLoadingEnabled = false;
}
public DbSet<Product> Products { get; set; }
public DbSet<ProductInfo> ProductInfos { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>() // one-to-one
.ToTable("Products")
.HasKey(e => e.Id)
.HasRequired(e => e.Info)
.WithRequiredDependent(e => e.Product);
modelBuilder.Entity<ProductInfo>() // map to the same table Products
.ToTable("Products")
.HasKey(e => e.Id);
base.OnModelCreating(modelBuilder);
}
}
}
答案 4 :(得分:0)
用此代码替换覆盖方法并检查
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>() // one-to-one
.ToTable("Products")
.HasKey(e => e.Id)
.HasRequired(e => e.Info)
.WithRequiredDependent(e => e.Product);
modelBuilder.Entity<ProductInfo>() // map to the same table Products
.ToTable("Products")
.HasKey(e => e.Id);
//add this code
modelBuilder.Entity<Product>()
.HasRequired(p => p.Photo) // "Photo" defined in Product class for ProductPhoto class's object name
.WithRequiredPrincipal(c => c.Product);// "Product" defined in ProductPhoto class for Product's class object name
base.OnModelCreating(modelBuilder);
}
答案 5 :(得分:0)
我知道这不是“正确的”答案,但是由于麻烦的是需要进行表拆分,并且在删除时会出错,所以我只用了一个很好的旧SQL命令:
DbContext.Database.ExecuteSqlCommand($"DELETE FROM Products WHERE Id = {id}");
当您花费数小时试图使一个小功能正常工作时,总是一个选择!