C# 使用guid主键忽略LINQ到SQL实体列名属性

C# 使用guid主键忽略LINQ到SQL实体列名属性,c#,sql-server,linq,sql-server-2005,linq-to-sql,C#,Sql Server,Linq,Sql Server 2005,Linq To Sql,我使用的是一个简单的实体类,使用LINQ to SQL(SQL Server 2005 SP3 x64) 这里只有两件有趣的事情: 类名和属性名与表名和列名不同 主键是Guid(唯一标识符) 下面是该表的外观: create table dbo.TBL_REGISTRATION ( TBL_REGISTRATION_PK uniqueidentifier primary key clustered rowguidcol default newid

我使用的是一个简单的实体类,使用LINQ to SQL(SQL Server 2005 SP3 x64)

这里只有两件有趣的事情:

  • 类名和属性名与表名和列名不同
  • 主键是Guid(唯一标识符)
  • 下面是该表的外观:

     create table dbo.TBL_REGISTRATION
        (
        TBL_REGISTRATION_PK uniqueidentifier primary key clustered
            rowguidcol
            default newid(),
        /* other columns ommited for brevity */ 
        )
    
    当我将此实体附加到表并提交对DataContext的更改时,LINQ堆栈将抛出SqlException:

    SqlException(0x80131904):列名“RegistrationID”无效

    LINQ似乎忽略了my RegistrationID属性上的列(Name=“TBL\u REGISTRATION\u PK”)属性。我花了一段时间用不同的属性装饰来装饰,试图让它发挥作用。最后,我决定使用一个私有的TBL_REGISTRATION_PK属性来包装我的RegistrationID属性,让LINQ开心

    [Table( Name="TBL_REGISTRATION" )]
    public sealed class Registration : IDataErrorInfo
    {
            public Guid RegistrationID { get; private set; }
            [Column( IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert )]
            private Guid TBL_REGISTRATION_PK { get { return RegistrationID; } set { RegistrationID = value; } }
        /* other properties ommited for brevity */
    }
    
    这很有效

    为什么第一种方式不起作用?我在这里做错了什么,还是这是LINQ缺陷?

    您尝试过使用该属性吗

    [Table( Name="TBL_REGISTRATION" )]
    public sealed class Registration : IDataErrorInfo
    {
            [Column( Name="TBL_REGISTRATION_PK", Storage="_RegistrationID", IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert )]
            public Guid RegistrationID { get { return _RegistrationID; } set { _RegistrationID = value; } }
    
            private Guid _RegistrationID;
        /* other properties ommited for brevity */
    }
    
    另请参见使用带有列名称的“存储”属性:

    [Column( Name="TBL_REGISTRATION_PK", Storage="TBL_REGISTRATION_PK", IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert )]
            public Guid RegistrationID { get { return _RegistrationID; } set { _RegistrationID = value; } }
    

    因为列的存储名称为TBL_REGISTRATION_PK。

    您的属性需要从“private set;”中删除“private”当您在VS2008中创建简写属性而不实现get/set时,编译器将为您创建私有成员变量(谁知道它的名称)。ColumnAttribute中的存储选项指定要使用的私有成员

    如果将setter标记为private并将getter设置为public(不要问我为什么),linqtosql不知道如何设置属性。如果希望将属性设置为只读,请像上面那样设置私有成员变量

    您可以通过如下方式编写它来清理它:

        [Table( Name="TBL_REGISTRATION" )]
        public sealed class Registration : IDataErrorInfo
        {
                public Guid RegistrationID { get { return _registrationID; } }
    
                [Column( IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert)]
                private Guid _registrationID; 
    }
    

    我发现解决这个问题的最佳解决方案是在类中创建一个私有Guid字段,该字段与数据库中的主键具有完全相同的名称,并将其用作符合框架指南命名约定的属性的支持字段

    // Primary key to TBL_REGISTRATIONT
    [Column( Name = "TBL_REGISTRATIONT_PK", IsDbGenerated = true, AutoSync = AutoSync.OnInsert )]
    public Guid RegistrationID
    {
        get
        {
            return TBL_REGISTRATIONT_PK;
        }
        private set
        {
            TBL_REGISTRATIONT_PK = value;
        }
    }
    [Column( IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert )]
    private Guid TBL_REGISTRATIONT_PK;
    

    这是LINQtoSQL中的一个bug。它在.NET4.0中是固定的

    参见Connect#381883:

    没有。好主意,但这显然不起作用:“无效的列名'RegistrationID'。”感谢您的参与,但这不起作用。它将导致在运行时引发InvalidOperationException,因为类中没有“TBL_REGISTRATION_PK”字段或属性。ColumnAttribute.Storage属性用于指示一个私有字段,该字段保存支持使用该属性装饰的属性的数据。我很高兴终于发现(a)我没有疯,(b)它正在被修复。
    // Primary key to TBL_REGISTRATIONT
    [Column( Name = "TBL_REGISTRATIONT_PK", IsDbGenerated = true, AutoSync = AutoSync.OnInsert )]
    public Guid RegistrationID
    {
        get
        {
            return TBL_REGISTRATIONT_PK;
        }
        private set
        {
            TBL_REGISTRATIONT_PK = value;
        }
    }
    [Column( IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert )]
    private Guid TBL_REGISTRATIONT_PK;