实体框架6,验证未按预期工作

时间:2019-02-18 10:23:34

标签: c# entity-framework entity-framework-6

我有以下一段代码

 var newPost = new Post()
                {
                    Activity = new Activity { Type = 1, ActivityTotalStatistic = new ActivityTotalStatistic() },
                    CreatedDate = oldPost.DateTimeCreated,
                    CategoryId = categoryId,
                    Title = oldPost.Name,
                    OwnerId = oldPost.UserID,
                    Slug = oldPost.Name,
                    LastUpdateDate = oldPost.DateTimeCreated,
                    PublishDate = oldPost.DateTimeCreated,
                    PostStatistic = new PostStatistic(),
                    PostItems = new List<PostItem>
                        {
                                new PostItem
                                {
                                    Activity = new Activity { Type = 2},<-- note this line of code
                                    CreatedDate = oldPost.DateTimeCreated,
                                    Title = oldPost.Name,
                                    Type = 1,
                                    Content = oldPost.Path
                                }
                            }

                    };

newDb.Posts.Add(newPost);
newDb.SaveChanges();

这是活动和统计信息表的SQL模式

create table ActivityTotalStatistics
(
    Id int primary key identity(1,1),
    NumberOfLikes int not null,
    NumberOfDislikes int not null,
    SumOfLikes int not null,
    CommentCount int not null
)

create table Activities
(
    Id int identity (1,1) primary key,
    Type int not null,
    ActivityTotalStatisticId int not null  
        foreign key references ActivityTotalStatistics(Id)
)

如您所见,每个活动都应该具有活动统计信息,因为外键不可为空,并且我的代码应该中断,因为发布项目中的活动没有实例化活动统计信息。

但是EF无法识别它。发生的情况是,该项目从该行代码接收到相同的活动统计信息

Activity = new Activity { Type = 1, ActivityTotalStatistic = new ActivityTotalStatistic() },

这是实体框架的有效行为吗?

更新 Activity.cs模型

public partial class Activity
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Activity()
        {
            this.ActivityLikes = new HashSet<ActivityLike>();
            this.Comments = new HashSet<Comment>();
            this.PostItems = new HashSet<PostItem>();
            this.Posts = new HashSet<Post>();
        }

        public int Id { get; set; }
        public int Type { get; set; }
        public int ActivityTotalStatisticId { get; set; }

        public virtual ActivityTotalStatistic ActivityTotalStatistic { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<ActivityLike> ActivityLikes { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Comment> Comments { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<PostItem> PostItems { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Post> Posts { get; set; }
    }

ActivityTotalStatistic.cs

public partial class ActivityTotalStatistic
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public ActivityTotalStatistic()
        {
            this.Activities = new HashSet<Activity>();
        }

        public int Id { get; set; }
        public int NumberOfLikes { get; set; }
        public int NumberOfDislikes { get; set; }
        public int SumOfLikes { get; set; }
        public int CommentCount { get; set; }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Activity> Activities { get; set; }
    }

1 个答案:

答案 0 :(得分:4)

  

这是实体框架的有效行为吗?

我不这么认为-不幸的是,对于这些跟踪行为,没有正式的文档/规范,但看起来像实现特定的副作用/缺陷(错误)。

理论价格:

仅当更改跟踪器包含具有自动生成的PK的单个 Added主实体,从属实体同时具有显式引用导航属性和FK属性时,才会发生全部具有默认值(“ 0”和null)。

在以下情况下不会发生

(1)有第二个Added主要实体:

newDb.Set<ActivityTotalStatistic>().Add(new ActivityTotalStatistic());

SaveChanges抛出DbUpdateException

  

无法确定“ Activity_ActivityTotalStatistic”关系的主要终点。添加的多个实体可能具有相同的主键。

不太用户友好,但仍然是例外。

(2)从属实体没有显式的FK属性,但是正确配置了必需的影子FK属性。 SaveChanges引发:

  

“ MyDbContext.Activities”中的实体参与“ Activity_ActivityTotalStatistic”关系。找到0个相关的'Activity_ActivityTotalStatistic_Target'。 1个预期为“ Activity_ActivityTotalStatistic_Target”。

虽然不是很友好,但还是有例外。

(3)引用导航属性已应用[Required]属性:

[Required]
public virtual ActivityTotalStatistic ActivityTotalStatistic { get; set; }

SaveChanges抛出包含ValidationException的{​​{1}},并带有(最终)用户友好消息:

  

ActivityTotalStatistic字段为必填字段。


回到原始情况。仅且仅在该特定情况下,EF会找到单个挂起的ValidationError主实体实例,并将其与具有AddedActivityTotalStatistic == null的所有挂起的从属实体相关联。

对我来说,所有这些都表明错误/意外的EF6行为。防止它的最好方法似乎是用ActivityTotalStatisticId == 0]属性修饰必需的参考导航属性,但是在像您这样的数据库优先(edmx)生成的实体模型中存在问题。