c# - Entity Framework 6,验证未按预期工作

标签 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() },

这是 Entity Framework 的有效行为吗?

更新 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; }
    }

最佳答案

Is this a valid behavior of Entity Framework?

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

理由:

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

如果满足以下条件,则不会发生:

(1) 还有第二个已添加主体实体:

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

SaveChanges 抛出 DbUpdateException:

Unable to determine the principal end of the 'Activity_ActivityTotalStatistic' relationship. Multiple added entities may have the same primary key.

不是很用户友好,但仍然是异常(exception)。

(2) 依赖实体没有显式 FK 属性,但正确配置了所需的影子 FK 属性。 SaveChanges 抛出:

Entities in 'MyDbContext.Activities' participate in the 'Activity_ActivityTotalStatistic' relationship. 0 related 'Activity_ActivityTotalStatistic_Target' were found. 1 'Activity_ActivityTotalStatistic_Target' is expected.

同样不是很用户友好,但仍然是异常(exception)。

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

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

SaveChanges 抛出包含 ValidationErrorValidationException 以及(最终)用户友好的消息:

The ActivityTotalStatistic field is required.


回到最初的案例。仅且仅在该特定情况下,EF 会找到单个待处理的 Added 主体实体实例,并将其与所有具有 ActivityTotalStatistic == nullActivityTotalStatisticId = 的待处理依赖实体关联起来。 = 0

对我来说,所有这些都表明存在错误/意外的 EF6 行为。防止这种情况的最佳方法似乎是使用 [Required] 属性装饰所需的引用导航属性,但这在像您这样的 Database First (edmx) 生成的实体模型中是有问题的。

关于c# - Entity Framework 6,验证未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54745047/

相关文章:

entity-framework-6 - ODP.net 12c release 3 : How to config Number(1, 0) 在某些情况下映射到 bool,在某些情况下映射到 int16

c# - 如何按位操作十六进制值?

entity-framework - Azure函数: Can compile but cannot run with custom datalayer library

c# - 如何更新 Entity Framework 中的相关实体

c# - 我想使用 Entity Framework + ASP Identity 但我不想让 EF 为我生成表

c# - 无效的列名称 ID-Entity Framework

c# - 查询超时怎么办?

c# - 我要处理我的 ODBCConnection

java - 使用 nunit 使用 jni4net 桥接代码运行测试

c# - Entity Framework 核心连接字符串 - 环境变量