【问题标题】:EF CORE 5.0.1 Configuring abstract class to be ignored as an model entity but access its properties in derived modelsEF CORE 5.0.1 配置抽象类作为模型实体被忽略,但在派生模型中访问其属性
【发布时间】:2021-03-20 04:28:33
【问题描述】:

我有一个抽象基类,它是所有派生(~100)类的基础。 这个基类应该不保存到数据库中,但它的属性应该作为派生类中的列公开 -> 实体模型。 在 Db 上下文代码(OnModel Creation 等)中,没有提及 BaseEntity - 仅提及其派生类。

在 3.0.1 中,这很好用。 BaseEntity 被忽略,仅提及的类(通过 DbSet 或 OnModelxxx 中)被配置为 TPH。

System.InvalidOperationException:无法为“BaseEntity”创建 DbSet,因为该类型未包含在上下文模型中。

如何恢复以前的行为?


我的基类:

public abstract class BaseEntity 
    {
        [Key]
        [GraphQLName("id")]
        [GraphQLNonNullType(IsNullable = true)]
        public Guid Identifier { get; set; } = Guid.NewGuid();

        [GraphQLNonNullType(IsNullable = true)]
        public DateTime CreatedDate { get; set; } = DateTime.UtcNow;

        [GraphQLNonNullType(IsNullable = true)]
        public DateTime LastModifiedDate { get; set; } = DateTime.UtcNow;

        [GraphQLNonNullType(IsNullable = true)]
        public DateTime DisplayDate { get; set; } = DateTime.UtcNow;


        public string DisplayName { get; set; } = string.Empty;

        public string DisplayText { get; set; } = string.Empty;

        public string DisplayDescription { get; set; } = string.Empty;

        public string TypeName { get; set; }
}

.....

派生类示例:

public class Document : BaseEntity
    {
        [GraphQLIgnore]
        public Organization Organization { get; set; }

        [GraphQLNonNullType(IsNullable = true)]
        public DocumentType DocumentType { get; set; }

        /// <summary>
        /// Mimetype of the document
        /// </summary>
        [GraphQLName("type")]
        [GraphQLNonNullType(IsNullable = true)]
        public string MimeType { get; set; }
}

保存代码 - 使用 BaseEntity - 在 SaveChangesAsync() 上引发异常

    public async Task<List<T>> Upsert<T>(List<T> baseEntities, bool isRaiseBaseEntityChangeEvent = true) where T : class
            {
                var entities = new HashSet<BaseEntity>();
    
                foreach (var b in baseEntities)
                {
                    entities.Add(b as BaseEntity);
                    TraverseGraph(b as BaseEntity, ref entities);
                }
    
                using (var context = GetDbInstance())
                {
                    try
                    {
                        foreach (var e in entities)
                        {
                            //exists in db
                            if (e.IsPersistedToDatabase == true)
                            {
    
                                context.Attach(e);
                                foreach (var entry in context.Entry(e).Properties)
                                {
                                    try
                                    {
                                        if (entry.Metadata.Name.Equals("CreatedDate"))
                                        {
                                            // Don't allow changing the CreatedDate on existing objects.
                                            entry.IsModified = false;
                                        }
                                        else if (entry.CurrentValue != null && !entry.Metadata.IsPrimaryKey())
                                        {
                                            entry.IsModified = true;
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        System.Diagnostics.Trace.WriteLine(ex.Message);
                                        continue;
                                    }
                                }
    
                            }
                            else
                            {
                                e.IsPersistedToDatabase = true;
                                context.Set<BaseEntity>().Add(e);
                            }
                        }
    
                        //make a copy for the change event
    
                        List<BaseEntityEntry> baseEntries = new List<BaseEntityEntry>();
                        foreach (var e in context.ChangeTracker.Entries())
                            baseEntries.Add(new BaseEntityEntry()
                            {
                                Entity = e.Entity as BaseEntity,
                                State = e.State
                            });
    
                        await context.SaveChangesAsync();
    
                        #region BaseEntity change event raising
                        if (isRaiseBaseEntityChangeEvent)
                        {
                            EventsPublisher.Instance.SignalEntityChange(new BaseEntityChangeEventArgs()
                            {
                                Entities = baseEntries
    
                            });
                        }
                        #endregion
    
                        return baseEntities;
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Trace.WriteLine(ex.Message);
                        throw ex;
                    }
                }
            }

【问题讨论】:

  • 显示产生异常的代码。
  • 这有点特殊 - 关键是在保存期间所有派生类都被引用为基本抽象类:code public async Task> Upsert(List baseEntities, bool isRaiseBaseEntityChangeEvent = true) where T : class code
  • 我怀疑这段代码在以前的 EFC 版本中是否有效,但这并不重要,因为 Set&lt;BaseEntity&gt;() 不是正确的调用。将 context.Set&lt;BaseEntity&gt;().Add(e); 替换为 context.Add(e);。
  • @ChrisCardinal Ivan Stoev 是正确的.....
  • 我刚刚添加了一个 Q/A 来解决这个问题。见stackoverflow.com/questions/65778874/…

标签: c# entity-framework-core


【解决方案1】:
ontext.Set<BaseEntity>()

肯定是错的。

随便用

context.Add(e);

或

context.Set<{ConcreteType}>.Add(e);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-07
    • 2017-08-23
    • 2017-10-05
    相关资源
    最近更新 更多