【问题标题】:Why is entity framework not respecting my data annotations?为什么实体框架不尊重我的数据注释?
【发布时间】:2015-08-31 16:10:53
【问题描述】:

为什么实体框架不尊重我的数据注释?

一点背景知识:我刚开始一份新工作,我的任务是向 ASP.net 项目添加实体框架。项目结构如下: Data.csproj -> 有我新添加的代码优先实体框架代码。这个项目将容纳我们的模型 MVC.csproj -> ClassLibrary,包含我们 MVC 结构的所有控制器。这个项目目前充斥着 MVC 领域。我添加了 OWIN 以及 UserStore、UserManager 和 SignInManager Web.vbproj -> 这是/曾经是一个 Asp.Net 网络表单项目,它混合了 MVC 和网络表单代码。根据我的老板系统架构师的说法,计划是在这个项目中除了 html 视图、css 和 javascript 之外什么都没有。我们目前正在将该项目从 asp.net webforms 迁移到上述 MVC 结构。

我正在使用 EntityFramework v6.1.1

在 Data.csproj 项目中,我定义了以下实体:

[Table("Terminals", Schema = "dbo")]
public class TerminalEx
{
    #region Constructors
    public TerminalEx()
    {

    }
    #endregion

    #region Public Properties
    [Key]
    public int TerminalId { get; set; }

    public string License { get; set; }

    [Column("TerminalName")]
    public string Name { get; set; }

    public string RootPublicDomainAddress { get; set; }
    public string CompanyName { get; set; }
    public int TimeZoneId { get; set; }
    public string Zip { get; set; }
    public string DispatchEmail { get; set; }

    [Column("useAutoAddlDrvPmt")]
    public byte UseAutoAddDriverPayment { get; set; }

    public byte UseTerminalAutoAssignment { get; set; }
    public byte UseMapCodes { get; set; }

    [Column("OEautoPopulateAccountNo")]
    public byte AutoPopulateAccountNumberForOrderEntry { get; set; }

    [Column("OEautoPopulateAddresses")]
    public byte AutoPopulateAddressesForOrderEntry { get; set; }
    #endregion
}

这是我的 DbContext:

public class XceleratorContext : DbContext
{
    public static void DoTest()
    {
        XceleratorContext db = null;
        try
        {
            db = new XceleratorContext();
            var bleh = db.Terminals.ToList();

            foreach (TerminalEx term in bleh)
            {
                System.Diagnostics.Debug.WriteLine(term.TerminalId);
                System.Diagnostics.Debug.WriteLine(term.Name);
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.ToString());
            throw;
        }
        finally
        {
            if (db != null)
            {
                db.Dispose();
                db = null;
            }
        }
    }

    #region Contructors
    public XceleratorContext()
        : base(ConfigurationManager.AppSettings["ConnectionString"])
    {
        Database.SetInitializer<XceleratorContext>(null);
        this.Database.Log += WriteLog;
    }

    private void WriteLog(string obj)
    {
        System.Diagnostics.Debug.WriteLine(obj);
    }
    #endregion

    #region Public Properties
    public virtual DbSet<TerminalEx> Terminals { get; set; }
    #endregion

    #region Encapsulation of DbSets
    public T Add<T>(T entity) where T : class
    {
        return Set<T>().Add(entity);
    }

    public T Attach<T>(T entity) where T : class
    {
        Set<T>().Attach(entity);
        Entry<T>(entity).State = EntityState.Modified;
        return entity;
    }

    public T Detach<T>(T entity) where T : class
    {
        Entry<T>(entity).State = EntityState.Detached;
        return entity;
    }

    public T Remove<T>(T entity) where T : class
    {
        if (Entry<T>(entity).State == EntityState.Detached)
        {
            Entry<T>(entity).State = EntityState.Deleted;
            return Entry<T>(entity).Entity;
        }
        else
            return Set<T>().Remove(entity);
    }
    #endregion

    #region Method Overrides
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<EFUser>();
        var terminalConfig = modelBuilder.Entity<TerminalEx>();

        //terminalConfig.Map(b => 
        //{
        //    b.Property(c => c.Name).HasColumnName("TerminalName");
        //    b.Property(c => c.UseAutoAddDriverPayment).HasColumnName("useAutoAddlDrvPmt");
        //    b.Property(c => c.AutoPopulateAccountNumberForOrderEntry).HasColumnName("OEautoPopulateAccountNo");
        //    b.Property(c => c.AutoPopulateAddressesForOrderEntry).HasColumnName("OEautoPopulateAddresses");                
        //}).ToTable("Terminals", "dbo").HasKey(d => d.TerminalId);

        // base.OnModelCreating(modelBuilder);
    }        
    #endregion

    #region Stored Proicedure Calls
    public IEnumerable<EFUser> GetUser(int? id = null, string userName = null, string passwordHash = null)
    {
        return this.Database.SqlQuery<EFUser>(
            " exec dbo.GetUser @id, @userName, @passwordHash ", 
            GetSqlParameter("id", System.Data.SqlDbType.Int, value: id),
            GetSqlParameter("userName", System.Data.SqlDbType.NVarChar, 100, userName),
            GetSqlParameter("passwordHash", System.Data.SqlDbType.NVarChar, 100, passwordHash));            
    }
    #endregion

    #region Private Methods
    private static SqlParameter GetSqlParameter<T>(string name, System.Data.SqlDbType type, int? size = null, T? value = null) where T : struct
    {
        var res = new SqlParameter(name, type) { Value = value ?? (object)DBNull.Value };

        if (size.HasValue)
            res.Size = size.Value;

        return res;
    }

    private static SqlParameter GetSqlParameter(string name, System.Data.SqlDbType type, int size, string value)
    {
        return new SqlParameter(name, type, size) { Value = value ?? (object)DBNull.Value };
    }
    #endregion
}

最后在 Web.vbproj 里面是 index.aspx.vb 的 Page_Load

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    Xcelerator.Data.BizObjects.XceleratorContext.DoTest()

End Sub

我的问题是我收到以下错误。我已经通过创建一个新的 asp.net webforms VB proj 并在索引页面的页面加载上调用相同的方法来测试我的代码,并且效果很好。我已经从 web.vbpoj 中删除了尽可能多的代码、引用和包,但我仍然遇到同样的错误。出于某种原因,仅在此 Web.vbproj 中,代码优先实体框架不尊重我的数据注释。

System.Data.Entity.Core.EntityCommandExecutionException 被捕获
HResult=-2146232004 消息=执行 命令定义。有关详细信息,请参阅内部异常。
来源=EntityFramework StackTrace: 在 System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand、CommandBehavior 行为) 在 System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan.Execute[TResultType](ObjectContext 上下文,ObjectParameterCollection 参数值) 在 System.Data.Entity.Core.Objects.ObjectQuery1.<>c__DisplayClass3.<GetResults>b__2() at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess) 在 System.Data.Entity.Core.Objects.ObjectQuery1.<>c__DisplayClass3.<GetResults>b__1() at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func1 手术) 在 System.Data.Entity.Core.Objects.ObjectQuery1.GetResults(Nullable1 forMergeOption) 在 System.Data.Entity.Core.Objects.ObjectQuery1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0() at System.Lazy1.CreateValue() 在 System.Lazy1.LazyInitValue() at System.Lazy1.get_Value() 在 System.Data.Entity.Internal.LazyEnumerator1.MoveNext() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 源) 在 C:\svonaRepo\XceleratorLocal 中的 Xcelerator.Data.BizObjects.XceleratorContext.DoTest() - 复制\Xcelerator.Data\BizObjects\XceleratorContext.cs:第 22 行
内部异常:System.Data.SqlClient.SqlException H结果=-2146232060 消息=无效的对象名称“dbo.TerminalExes”。 Source=.Net SqlClient 数据提供者 错误代码=-2146232060 班级=16 行号=1 数量=208 程序="" 服务器=KSS-DT18 状态=1 堆栈跟踪: 在 System.Data.SqlClient.SqlConnection.OnError(SqlException 异常, Boolean breakConnection, Action1 wrapCloseInAction) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) 在 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) 在 System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,SqlCommand cmdHandler,SqlDataReader 数据流, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean & dataReady) 在 System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() 在 System.Data.SqlClient.SqlDataReader.get_MetaData() 在 System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior,字符串 resetOptionsString) 在 System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior、RunBehavior runBehavior、布尔 returnStream、布尔 异步,Int32 超时,任务和任务,布尔 asyncWrite,SqlDataReader ds, 布尔值 describeParameterEncryptionRequest) 在 System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior、RunBehavior、runBehavior、布尔返回流、字符串 方法,TaskCompletionSource1 completion, Int32 timeout, Task& task, Boolean asyncWrite) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<>c__DisplayClassb.<Reader>b__8() at System.Data.Entity.Infrastructure.Interception.InternalDispatcher1.Dispatch[TInterceptionContext,TResult](Func1 operation, TInterceptionContext interceptionContext, Action1 正在执行,Action`1 已执行) 在 System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand 命令,DbCommandInterceptionContext 拦截上下文) 在 System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(CommandBehavior 行为) 在 System.Data.Common.DbCommand.ExecuteReader(CommandBehavior 行为) 在 System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand、CommandBehavior 行为) 内部异常:

【问题讨论】:

    标签: c# asp.net .net entity-framework ef-code-first


    【解决方案1】:

    这部分代码说,“我想用 POCO 做 Fluent Code First”,也就是说,我的 POCO 没有注释,这是我想要的映射自定义。

    然后您继续对映射进行任何自定义。因此,您将获得默认映射。

    #region Method Overrides
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<EFUser>();
        var terminalConfig = modelBuilder.Entity<TerminalEx>();
    
        //terminalConfig.Map(b => 
        //{
        //    b.Property(c => c.Name).HasColumnName("TerminalName");
        //    b.Property(c => c.UseAutoAddDriverPayment).HasColumnName("useAutoAddlDrvPmt");
        //    b.Property(c => c.AutoPopulateAccountNumberForOrderEntry).HasColumnName("OEautoPopulateAccountNo");
        //    b.Property(c => c.AutoPopulateAddressesForOrderEntry).HasColumnName("OEautoPopulateAddresses");                
        //}).ToTable("Terminals", "dbo").HasKey(d => d.TerminalId);
    
        // base.OnModelCreating(modelBuilder);
    }        
    #endregion
    

    只需删除 DbContext 的那一部分,一切都会好起来的。

    【讨论】:

    • 您是在告诉我删除对 OnModelCreating 的覆盖?我认为这是不正确的,因为当我从我的 asp.net vb 测试项目中调用 XceleratorContext.DoTest() 时,相同的代码可以工作。我发现我需要调用modelBuilder.Entity&lt;ClassName&gt;(),即使我没有使用 fluent API
    • @scottKSS 听起来你甚至没有尝试过。如果是这样,我试图帮助你是没有意义的。
    • 对不起,如果我听起来像是在吹你的话。我不是。我没有尝试过,因为我从过去的经验中知道,如果您没有在模型构建器中定义您的实体,那么您将无法对它们执行 CRUD 操作。也许我对 EF 的了解还不够。如果我用public virtual DbSet&lt;TerminalEx&gt; Terminals { get; set; } 声明 TerminalEx,我可以避免在 OnModelCreating 中定义它吗? EFUser 呢?我没有为此定义 DbSet。我一般封装我的 DbSet。我刚刚为 TerminalEx 暴露了一个 DbSet,所以我不必为它定义一个 Get 方法。
    【解决方案2】:

    我终于找到了问题所在。 Web.vbproj 项目包含在项目中的 NuGet 包文件夹。通过从项目中排除该文件夹,我的 EF 代码/方法按预期工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多