Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/visual-studio-2010/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Entity framework EF6代码先继承后引用_Entity Framework_Inheritance_Ef Code First_Table Per Type - Fatal编程技术网

Entity framework EF6代码先继承后引用

Entity framework EF6代码先继承后引用,entity-framework,inheritance,ef-code-first,table-per-type,Entity Framework,Inheritance,Ef Code First,Table Per Type,我首先使用EntityFramework6代码编写DAL。我有一个表每类型继承结构 我有四门课:AbstractMaster、ConcreteMaster、AbstractDetail和ConcreteDetail。直观地说,具体类继承自抽象类,抽象类和具体类的主类和细节类之间存在一对多的关系。每个类型模式的表格是一项要求 如果我向ConcreteMaster实体添加ConcreteDetail并保存更改(DbContext),我将收到一个外键错误。原因是已设置从ConcreteDetail到C

我首先使用EntityFramework6代码编写DAL。我有一个表每类型继承结构

我有四门课:AbstractMaster、ConcreteMaster、AbstractDetail和ConcreteDetail。直观地说,具体类继承自抽象类,抽象类和具体类的主类和细节类之间存在一对多的关系。每个类型模式的表格是一项要求

如果我向ConcreteMaster实体添加ConcreteDetail并保存更改(DbContext),我将收到一个外键错误。原因是已设置从ConcreteDetail到ConcreteMaster的反向引用,但尚未设置从AbstractDetail到AbstractMaster的反向引用

如果在“抽象”级别删除一对多关系,则测试通过。虽然数据完整性仍然在“具体”级别强制执行,但数据库仍然缺少合法的外键。似乎是一个有效的用例

有什么建议吗

谢谢,
John

对主类的集合导航属性使用
ObservableCollection
。为
ConcreteMaster
类中每个集合的
CollectionChanged
事件实现处理程序方法。这里的想法是,当一个项目添加或删除到一个集合中时,您将从另一个集合中添加/删除相同的项目:

AbstractMaster类:

[Table( "AbstractMaster" )]
public abstract class AbstractMaster
{
    public int Id { get; set; }

    public virtual ObservableCollection<AbstractDetail> AbstractDetails { get; private set; }

    public AbstractMaster()
    {
        AbstractDetails = new ObservableCollection<AbstractDetail>();
    }
}
[Table( "ConcreteMaster" )]
public class ConcreteMaster : AbstractMaster
{
    public virtual ObservableCollection<ConcreteDetail> ConcreteDetails { get; private set; }

    public ConcreteMaster()
    {
        ConcreteDetails = new ObservableCollection<ConcreteDetail>();

        ConcreteDetails.CollectionChanged += ConcreteDetails_CollectionChanged;

        base.AbstractDetails.CollectionChanged += AbstractDetails_CollectionChanged;
    }

    void AbstractDetails_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
    {
        var newDetails = new List<ConcreteDetail>();
        var oldDetails = new List<ConcreteDetail>();

        bool nonConcreteDetailAdded = false;

        switch( e.Action )
        {
            case NotifyCollectionChangedAction.Reset:
                var newCollection = sender as ReadOnlyObservableCollection<AbstractDetail>;
                nonConcreteDetailAdded = !newCollection.All( ad => ad is ConcreteDetail );

                if( !nonConcreteDetailAdded )
                {
                    newDetails.AddRange( e.NewItems.Cast<ConcreteDetail>() );
                }
                break;
            default:
                if( null != e.OldItems )
                {
                    oldDetails.AddRange( e.OldItems.Cast<ConcreteDetail>() );
                }

                if( null != e.NewItems )
                {
                    nonConcreteDetailAdded = !e.NewItems.Cast<AbstractDetail>().All( ad => ad is ConcreteDetail );

                    if( !nonConcreteDetailAdded )
                    {
                        newDetails.AddRange( e.NewItems.Cast<ConcreteDetail>() );
                    }
                }
                break;
        }

        if( nonConcreteDetailAdded )
        {
            throw new InvalidOperationException( "An object of a type not derived from ConcreteDetail was added to the AbstractDetails property of a ConcreteMaster object's base class" );
        }

        foreach( var removed in oldDetails )
        {
            if( ConcreteDetails.Contains( removed ) )
            {
                ConcreteDetails.Remove( removed );
            }
        }

        foreach( var added in newDetails )
        {
            if( !ConcreteDetails.Contains( added ) )
            {
                ConcreteDetails.Add( added );
            }
        }
    }

    void ConcreteDetails_CollectionChanged( object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e )
    {
        var newDetails = new List<AbstractDetail>();
        var oldDetails = new List<AbstractDetail>();

        switch( e.Action )
        {
            case NotifyCollectionChangedAction.Reset:
                var newCollection = sender as ReadOnlyObservableCollection<AbstractDetail>;
                base.AbstractDetails.Clear();
                newDetails.AddRange( newCollection );
                break;
            default:
                if( null != e.OldItems )
                {
                    oldDetails.AddRange( e.OldItems.Cast<AbstractDetail>() );
                }

                if( null != e.NewItems )
                {
                    newDetails.AddRange( e.NewItems.Cast<AbstractDetail>() );
                }
                break;
        }

        foreach( var removed in oldDetails )
        {
            if( base.AbstractDetails.Contains( removed ) )
            {
                base.AbstractDetails.Remove( removed );
            }
        }

        foreach( var added in newDetails )
        {
            if( !base.AbstractDetails.Contains( added ) )
            {
                base.AbstractDetails.Add( added );
            }
        }
    }
}
最后,在
ConcreteDetail
类中,在
ConcreteMaster
属性的setter中设置
base.AbstractMaster
属性,并向
base.AbstractMaster
添加事件处理程序,该事件处理程序将在
base.AbstractMaster
更改时更新
this.ConcreteMaster

[Table( "ConcreteDetail" )]
public class ConcreteDetail : AbstractDetail
{
    private ConcreteMaster _concreteMaster = null;
    public ConcreteMaster ConcreteMaster 
    {
        get
        {
            return _concreteMaster;
        }
        set
        {
            if( value != _concreteMaster )
            {
                _concreteMaster = value;
                base.AbstractMaster = _concreteMaster;
            }
        }
    }

    public ConcreteDetail()
    {
        base.PropertyChanged += ConcreteDetail_PropertyChanged;
    }

    void ConcreteDetail_PropertyChanged( object sender, PropertyChangedEventArgs e )
    {
        if( e.PropertyName == "AbstractMaster" )
        {
            var master = base.AbstractMaster;

            if( null == master )
            {
                _concreteMaster = null;
            }
            else if( master is ConcreteMaster )
            {
                _concreteMaster = master as ConcreteMaster;
            }
            else
            {
                throw new InvalidOperationException( "AbstractMaster property of a ConcreteDetail object's base class was set to an instance of a class that does not derive from ConcreteDetail" );
            }
        }
    }
}
我已使用以下代码对此进行了测试:

class Program
{
    static void Main(string[] args)
    {
        using( var db = new TestEntities() )
        {
            var master = new ConcreteMaster();

            var details = new[]{
                new ConcreteDetail() { Id = 1 },
                new ConcreteDetail() { Id = 2 },
                new ConcreteDetail() { Id = 3 },
                new ConcreteDetail() { Id = 4 }
            };

            master.AbstractDetails.Add( details[ 0 ] );
            master.ConcreteDetails.Add( details[ 1 ] );

            details[ 2 ].AbstractMaster = master;
            details[ 3 ].ConcreteMaster = master;

            db.ConcreteMasters.Add( master );
            db.AbstractDetails.Add( details[ 2 ] );
            db.ConcreteDetails.Add( details[ 3 ] );

            db.SaveChanges();
        }

        using( var db = new TestEntities() )
        {
            var concreteMaster = db.ConcreteMasters.Single();
            var abstractMaster = db.AbstractMasters.Single();

            Action<string, IEnumerable<AbstractDetail>> outputDelegate = ( string header, IEnumerable<AbstractDetail> details ) =>
                {
                    if( details.Count() > 0 )
                    {
                        Console.WriteLine( "{0}: {1}", header, string.Join( ", ", details.Select( ad => ad.Id.ToString() ) ) );
                    }
                    else
                    {
                        Console.WriteLine( "{0}: <empty>", header );
                    }
                };

            // 1, 2, 3, 4
            outputDelegate( "AbstractMaster.AbstractDetails", abstractMaster.AbstractDetails );
            outputDelegate( "ConcreteMaster.ConcreteDetails", concreteMaster.ConcreteDetails );

            // remove Id == 4 by way of removing from abstract collection
            abstractMaster.AbstractDetails.Remove( abstractMaster.AbstractDetails.Single( ad => ad.Id == 4 ) );
            db.SaveChanges();

            // 1, 2, 3
            outputDelegate( "AbstractMaster.AbstractDetails", abstractMaster.AbstractDetails );
            outputDelegate( "ConcreteMaster.ConcreteDetails", concreteMaster.ConcreteDetails );

            // remove Id == 3 by way of removing from concrete collection
            concreteMaster.ConcreteDetails.Remove( concreteMaster.ConcreteDetails.Single( cd => cd.Id == 3 ) );
            db.SaveChanges();

            // 1, 2
            outputDelegate( "AbstractMaster.AbstractDetails", abstractMaster.AbstractDetails );
            outputDelegate( "ConcreteMaster.ConcreteDetails", concreteMaster.ConcreteDetails );

            // remove Id == 2 by way of removing AbstractDetail from DbSet<AbstractDetail>
            db.AbstractDetails.Remove( abstractMaster.AbstractDetails.Single( ad => ad.Id == 2 ) );
            db.SaveChanges();

            // 1
            outputDelegate( "AbstractMaster.AbstractDetails", abstractMaster.AbstractDetails );
            outputDelegate( "ConcreteMaster.ConcreteDetails", concreteMaster.ConcreteDetails );

            // remove Id == 1 by wa of removing ConcreteDetail from DbSet<ConcreteDetail>
            db.ConcreteDetails.Remove( concreteMaster.ConcreteDetails.Single( cd => cd.Id == 1 ) );
            db.SaveChanges();

            // <empty>
            outputDelegate( "AbstractMaster.AbstractDetails", abstractMaster.AbstractDetails );
            outputDelegate( "ConcreteMaster.ConcreteDetails", concreteMaster.ConcreteDetails );
        }

        var input = Console.ReadLine();
    }
}
类程序
{
静态void Main(字符串[]参数)
{
使用(var db=newtestentities())
{
var master=新的ConcreteMaster();
var详细信息=新[]{
新建ConcreteDetail(){Id=1},
新建ConcreteDetail(){Id=2},
新建ConcreteDetail(){Id=3},
新建ConcreteDetail(){Id=4}
};
master.AbstractDetails.Add(details[0]);
master.ConcreteDetails.Add(详情[1]);
详细信息[2]。AbstractMaster=master;
详细信息[3]。混凝土主节点=主节点;
db.ConcreteMasters.Add(master);
db.AbstractDetails.Add(详情[2]);
db.ConcreteDetails.Add(详情[3]);
db.SaveChanges();
}
使用(var db=newtestentities())
{
var concreteMaster=db.ConcreteMasters.Single();
var abstractMaster=db.AbstractMasters.Single();
Action outputDelegate=(字符串头,IEnumerable详细信息)=>
{
如果(details.Count()>0)
{
Console.WriteLine(“{0}:{1}”,标题,string.Join(“,”,details.Select(ad=>ad.Id.ToString());
}
其他的
{
WriteLine(“{0}:”,标头);
}
};
// 1, 2, 3, 4
outputDelegate(“AbstractMaster.AbstractDetails”,AbstractMaster.AbstractDetails);
outputDelegate(“ConcreteMaster.ConcreteDetails”,ConcreteMaster.ConcreteDetails);
//通过从抽象集合中移除,移除Id==4
abstractMaster.AbstractDetails.Remove(abstractMaster.AbstractDetails.Single(ad=>ad.Id==4));
db.SaveChanges();
// 1, 2, 3
outputDelegate(“AbstractMaster.AbstractDetails”,AbstractMaster.AbstractDetails);
outputDelegate(“ConcreteMaster.ConcreteDetails”,ConcreteMaster.ConcreteDetails);
//通过从混凝土集合中移除的方式移除Id==3
concreteMaster.ConcreteDetails.Remove(concreteMaster.ConcreteDetails.Single(cd=>cd.Id==3));
db.SaveChanges();
// 1, 2
outputDelegate(“AbstractMaster.AbstractDetails”,AbstractMaster.AbstractDetails);
outputDelegate(“ConcreteMaster.ConcreteDetails”,ConcreteMaster.ConcreteDetails);
//通过从DbSet中删除AbstractDetail,删除Id==2
Remove(abstractMaster.AbstractDetails.Single(ad=>ad.Id==2));
db.SaveChanges();
// 1
outputDelegate(“AbstractMaster.AbstractDetails”,AbstractMaster.AbstractDetails);
outputDelegate(“ConcreteMaster.ConcreteDetails”,ConcreteMaster.ConcreteDetails);
//从数据库集中删除ConcreteDetail的wa将删除Id==1
db.ConcreteDetails.Remove(concreteMaster.ConcreteDetails.Single(cd=>cd.Id==1));
db.SaveChanges();
// 
outputDelegate(“AbstractMaster.AbstractDetails”,AbstractMaster.AbstractDetails);
outputDelegate(“ConcreteMaster.ConcreteDetails”,ConcreteMaster.ConcreteDetails);
}
var input=Console.ReadLine();
}
}
class Program
{
    static void Main(string[] args)
    {
        using( var db = new TestEntities() )
        {
            var master = new ConcreteMaster();

            var details = new[]{
                new ConcreteDetail() { Id = 1 },
                new ConcreteDetail() { Id = 2 },
                new ConcreteDetail() { Id = 3 },
                new ConcreteDetail() { Id = 4 }
            };

            master.AbstractDetails.Add( details[ 0 ] );
            master.ConcreteDetails.Add( details[ 1 ] );

            details[ 2 ].AbstractMaster = master;
            details[ 3 ].ConcreteMaster = master;

            db.ConcreteMasters.Add( master );
            db.AbstractDetails.Add( details[ 2 ] );
            db.ConcreteDetails.Add( details[ 3 ] );

            db.SaveChanges();
        }

        using( var db = new TestEntities() )
        {
            var concreteMaster = db.ConcreteMasters.Single();
            var abstractMaster = db.AbstractMasters.Single();

            Action<string, IEnumerable<AbstractDetail>> outputDelegate = ( string header, IEnumerable<AbstractDetail> details ) =>
                {
                    if( details.Count() > 0 )
                    {
                        Console.WriteLine( "{0}: {1}", header, string.Join( ", ", details.Select( ad => ad.Id.ToString() ) ) );
                    }
                    else
                    {
                        Console.WriteLine( "{0}: <empty>", header );
                    }
                };

            // 1, 2, 3, 4
            outputDelegate( "AbstractMaster.AbstractDetails", abstractMaster.AbstractDetails );
            outputDelegate( "ConcreteMaster.ConcreteDetails", concreteMaster.ConcreteDetails );

            // remove Id == 4 by way of removing from abstract collection
            abstractMaster.AbstractDetails.Remove( abstractMaster.AbstractDetails.Single( ad => ad.Id == 4 ) );
            db.SaveChanges();

            // 1, 2, 3
            outputDelegate( "AbstractMaster.AbstractDetails", abstractMaster.AbstractDetails );
            outputDelegate( "ConcreteMaster.ConcreteDetails", concreteMaster.ConcreteDetails );

            // remove Id == 3 by way of removing from concrete collection
            concreteMaster.ConcreteDetails.Remove( concreteMaster.ConcreteDetails.Single( cd => cd.Id == 3 ) );
            db.SaveChanges();

            // 1, 2
            outputDelegate( "AbstractMaster.AbstractDetails", abstractMaster.AbstractDetails );
            outputDelegate( "ConcreteMaster.ConcreteDetails", concreteMaster.ConcreteDetails );

            // remove Id == 2 by way of removing AbstractDetail from DbSet<AbstractDetail>
            db.AbstractDetails.Remove( abstractMaster.AbstractDetails.Single( ad => ad.Id == 2 ) );
            db.SaveChanges();

            // 1
            outputDelegate( "AbstractMaster.AbstractDetails", abstractMaster.AbstractDetails );
            outputDelegate( "ConcreteMaster.ConcreteDetails", concreteMaster.ConcreteDetails );

            // remove Id == 1 by wa of removing ConcreteDetail from DbSet<ConcreteDetail>
            db.ConcreteDetails.Remove( concreteMaster.ConcreteDetails.Single( cd => cd.Id == 1 ) );
            db.SaveChanges();

            // <empty>
            outputDelegate( "AbstractMaster.AbstractDetails", abstractMaster.AbstractDetails );
            outputDelegate( "ConcreteMaster.ConcreteDetails", concreteMaster.ConcreteDetails );
        }

        var input = Console.ReadLine();
    }
}