C# 删除在多个实体上拆分的表行时出错

C# 删除在多个实体上拆分的表行时出错,c#,entity-framework,C#,Entity Framework,我想删除在两个实体上拆分的表行 如果我试图删除主实体,则在我未使用上下文.Entry(…).Reference加载相关的其他实体之前,会出现一个错误 当我要删除整行时,在之前检索相关实体有点傻吗 如果我对context.Entry(…)行进行注释,则会出现以下错误 遇到无效数据。缺少必需的关系。检查 状态项以确定约束冲突的来源 我在下面添加代码。请有人帮我删除拆分的实体,而不必在之前“加载”相关实体,好吗 using System.Data.Entity; using System.Linq

我想删除在两个实体上拆分的表行

如果我试图删除主实体,则在我未使用
上下文.Entry(…).Reference加载相关的其他实体之前,会出现一个错误

当我要删除整行时,在之前检索相关实体有点傻吗

如果我对
context.Entry(…)
行进行注释,则会出现以下错误

遇到无效数据。缺少必需的关系。检查 状态项以确定约束冲突的来源

我在下面添加代码。请有人帮我删除拆分的实体,而不必在之前“加载”相关实体,好吗

 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);
     }
   }
}
使用System.Data.Entity;
使用System.Linq;
名称空间拆分
{
班级计划
{
静态void Main(字符串[]参数)
{
使用(var context=new DataContext())
{
var product=新产品()
{
Name=“我的文章”,
照片=新产品照片(){PhotoUrl=”http://myfoto.jpg" }
};
context.Products.Add(产品);
SaveChanges();
}
使用(var context=new DataContext())
{
var product=context.Products.First();
//context.Entry(product.Reference(e=>e.Photo.Load();
context.Products.Remove(产品);
SaveChanges();
}
}
}
类产品
{
公共虚拟整数Id{get;set;}
公共虚拟字符串名称{get;set;}
公共虚拟产品照片{get;set;}
}
班级产品照片
{
公共虚拟int ProductId{get;set;}
公共虚拟字符串PhotoUrl{get;set;}
公共虚拟产品产品{get;set;}
}
类DataContext:DbContext
{
公共数据上下文()
:base(“name=DefaultConnection”)
{
Configuration.ProxyCreationEnabled=false;
Configuration.LazyLoadingEnabled=false;
}
公共数据库集产品{get;set;}
公共DbSet ProductPhotos{get;set;}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
modelBuilder.Entity()
.ToTable(“产品”)
.HasKey(e=>e.Id)
.has必需(e=>e.Photo)
.具有所需的委托人(e=>e.Product);
modelBuilder.Entity()
.ToTable(“产品”)
.HasKey(e=>e.ProductId);
基于模型创建(modelBuilder);
}
}
}

可能像这样装载产品:

var product = context.Products.Include(x => x.Photo).First();

保存一行,但仍将从数据库加载照片。

尝试将级联删除规则添加到模型中。数据库中必须有相应的删除规则,以避免将依赖项加载到内存中

最好的方法是使用存根实体:仅具有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();

如果您知道
产品
的Id,您甚至可以通过只创建两个存根来删除
产品
及其
产品照片

嗨,格特·阿诺德建议的解决方法是在内存中 存根一个用于实体,另一个用于相关子实体 我粘贴了一个新的代码,该代码可以正常工作(参见注释)

我用Gert Arnold提出的想法发布了解决方案,也许代码可以优化,我试着让它尽可能通用

如果您的实体包含任何并发令牌,那么这些属性也是 用于构造DELETE语句。您仍然可以使用存根实体 方法,但需要为并发令牌设置值 属性也是如此

引自:“编程实体框架:DbContext” 作者:朱莉娅·勒曼和罗恩·米勒(O'Reilly)。版权所有2012朱莉娅·勒曼和 罗文·米勒,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);
        }

    }
}
使用系统;
使用System.Data.Entity;
使用System.Linq;
运用系统反思;
名称空间拆分
{
班级计划
{
静态void Main()
{
SetInitializer(新的DropCreateDatabaseAlways());
const int id=1;
const string split=“Info”//约定:如果要删除的实体具有Info属性,则该行已被拆分
使用(var context=new DataContext())//添加
{
var产品=新产品
{
Name=“我的文章1”,
信息=新产品信息{PhotoUrl=”http://myphoto.jpg“}//添加实体时,子实体必须包含在图形中
};
context.Products.Add(产品);
SaveChanges();
}
使用(var context=new DataContext())
{
var product=context.Products.Find(id);
context.Entry(product).Reference(e=>e.Info).Load();//添加实体时,子实体可以包含在图形中,也可以不包含在图形中,如果我们不打算修改它,则无需包含它
product.Name=“我的文章1”;
product.Info.PhotoUrl=“HTTP://MYPHOTO.JPG”;
context.Entry(product.State=EntityState.Modified;
SaveChanges();
}
使用(var context=new DataContext())
{
PropertyInfo PropertyInfo;
context.Products.Find(id);//取消注释将其带到内存并使用内存中的实体进行测试
var entity=context.Products.Local.FirstOrDefault(e=>e.Id==Id);
context.Entry(entity.Reference(e=>e.Info).Load();
if(entity!=null)//内存中已有一个实体
{
propertyInfo=entity.GetType().GetProperty(拆分);//合同
if(propertyInfo!=null)
{
var subEntity=propertyInfo.GetValue(实体);
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);
}
DbContext.Database.ExecuteSqlCommand($"DELETE FROM Products WHERE Id = {id}");