Entity framework EF 4.4防止自动生成导航属性和/或关系

Entity framework EF 4.4防止自动生成导航属性和/或关系,entity-framework,entity-framework-4,Entity Framework,Entity Framework 4,我使用EF启动了一个db模式,在尝试手动修改CLR和/或db表时遇到了多个问题。第一个是EF放在表中的“Employee_ID”列。我删除了它、dbo.EdmMetaData和dbo.\u MigrationHistory表,并摸索出了由此产生的运行时错误。现在,我正在处理以下错误: 引用约束中的依赖属性映射到存储生成的列。栏:“员工ID”。 我的实现使用具有3个计算列的TimeCardEntity CLR。这些列恰好映射到另一个表的主键。另一张表是EmployeeRecord 目标)我不希望E

我使用EF启动了一个db模式,在尝试手动修改CLR和/或db表时遇到了多个问题。第一个是EF放在表中的“Employee_ID”列。我删除了它、dbo.EdmMetaData和dbo.\u MigrationHistory表,并摸索出了由此产生的运行时错误。现在,我正在处理以下错误:

引用约束中的依赖属性映射到存储生成的列。栏:“员工ID”。

我的实现使用具有3个计算列的TimeCardEntity CLR。这些列恰好映射到另一个表的主键。另一张表是EmployeeRecord

目标)我不希望EF自动映射这3列。由于EF提供的复杂性,我打算自己填充它们,但我不能告诉EF停止创建导航关系和/或引用约束

点#1)我有一个EmployeeRecord表,它有一个Guid ID主键,它映射到CLR类EmployeeRecord

第2点)我有一个TimeCardEntity表,它有3个计算列,分别称为EmployeeID、ManagerID、DivisionManagerID,它们与EmployeeRecord相关。所有都声明为空,但EmployeeID是必需的,显然,因为如果不声明员工,您就无法拥有时间卡。ManagerID和ManagerID分区稍后将被填充

第3点)请不要问我“为什么计算这些?”因为这是有原因的。我一直觉得这与这个问题有关。简而言之,计算出的EmployeeID(无论是员工、经理还是部门经理)存储在xml属性中,包含员工的批准和签名数据,这提供了不可否认性

第4点)我有3个存储函数,分别称为fxGetEmployeeID(xml)、fxGetManagerID(xml)和GetDivisionManagerId(xml)。其中每一个都分别用于计算列EmployeeID、ManagerID和DivisionManagerID

以下是为简洁起见而简化的类声明:

    public enum TimeCardEmployeeTypeEnum {
    Employee,
    Manager,
    DivisionManager
}


[DataContract]
[Serializable]
[Table("EmployeeRecord", Schema = "TimeCard")]
public class EmployeeRecord {

                                        #region Exposed Propert(y|ies)

[DataMember]
public Guid ID { get; set; }

/// <summary>
/// Customers internal company employee ID.  Can be null, SSN, last 4, or what ever...
/// I included it just in case it was part of my pains...
/// </summary>
[CustomValidation(typeof(ModelValidator), "EmployeeRecord_EmployeeID", ErrorMessage = "Employee ID is not valid.")]
public string EmployeeID { get; set; }

#endregion
}


[DataContract]
[Serializable]
[Table("TimeCardEntry", Schema = "TimeCard")]
public class TimeCardEntry {

                #region Member Field(s)

[NonSerialized]
XDocument m_TimeEntries;

#endregion

                                            #region Con/Destructor(s)

public TimeCardEntry() {
    this.m_TimeEntries = "<root />".ToXDocument();
}

public TimeCardEntry(Guid employeeID) {
    if (employeeID == Guid.Empty)
        throw new ArgumentNullException("employeeID");
    this.m_TimeEntries = "<root />".ToXDocument();
    this.EmployeeID = employeeID;
}

#endregion

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        #region Exposed Propert(y|ies)

[NotMapped]
[IgnoreDataMember]
public XDocument TimeEntries {
    get {
        if (this.m_TimeEntries == null) {
            if (!string.IsNullOrEmpty(this.TimeEntriesXml))
                this.m_TimeEntries = this.TimeEntriesXml.ToXDocument();
        }
        return this.m_TimeEntries;
    }
    set {

        this.m_TimeEntries = value;
        if (this.m_TimeEntries != null)
            this.TimeEntriesXml = this.m_TimeEntries.ToString();
        else
            this.TimeEntriesXml = null;
        this.OnPropertyChanged("TimeEntriesXml");
        this.OnPropertyChanged("TimeEntries");
    }
}

[DataMember]
[EditorBrowsable(EditorBrowsableState.Never)]
[Required]
public string TimeEntriesXml {
    get {
        if (this.m_TimeEntries == null)
            return null;
        return this.m_TimeEntries.ToString();
    }
    set {
        this.m_TimeEntries = value.ToXDocument();
        this.OnPropertyChanged("TimeEntriesXml");
        this.OnPropertyChanged("TimeEntries");
    }
}

[IgnoreDataMember]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Computed)]
public Guid? EmployeeID {
    get {
        var attribute = this.m_TimeEntries.Root.Attribute("EmployeeID");
        if (attribute != null)
            return (Guid)attribute;
        return null;
    }
    set {

        if (this.ValidateSignature(TimeCardEmployeeTypeEnum.Manager))
            throw new ArgumentException("Property cannot be changed once the manager signature has been set.", "EmployeeID");

        if (value != null && value.Value != Guid.Empty)
            this.m_TimeEntries.Root.SetAttributeValue("EmployeeID", value);
        else {
            var attribute = this.m_TimeEntries.Root.Attribute("EmployeeID");
            if (attribute != null)
                attribute.Remove();
        }
        this.OnPropertyChanged("EmployeeID");
    }
}

public virtual EmployeeRecord Employee { get; set; }

[NotMapped]
[IgnoreDataMember]
public DateTime? EmployeeApprovalDate {
    get {
        var attribute = this.m_TimeEntries.Root.Attribute("EmployeeApprovalDate");
        if (attribute != null)
            return (DateTime)attribute;
        return null;
    }
    set {

        if (this.ValidateSignature(TimeCardEmployeeTypeEnum.Manager))
            throw new ArgumentException("Property cannot be changed once the manager signature has been set.", "EmployeeApprovalDate");

        if (value.HasValue)
            this.m_TimeEntries.Root.SetAttributeValue("EmployeeApprovalDate", value);
        else {
            var attribute = this.m_TimeEntries.Root.Attribute("EmployeeApprovalDate");
            if (attribute != null)
                attribute.Remove();
        }
        this.OnPropertyChanged("EmployeeApprovalDate");
    }
}

[NotMapped]
[IgnoreDataMember]
public byte[] EmployeeSignature {
    get {
        var attribute = this.m_TimeEntries.Root.Attribute("EmployeeSignature");
        if (attribute != null)
            return Convert.FromBase64String((string)attribute);
        return null;
    }
    set {

        if (this.ValidateSignature(TimeCardEmployeeTypeEnum.Manager))
            throw new ArgumentException("Property cannot be changed once the manager signature has been set.", "EmployeeSignature");

        if (value != null) {
            if (value.Length > 1024)
                throw new ArgumentException("Signature cannot be larger than 1KB.", "EmployeeSignature");
            this.m_TimeEntries.Root.SetAttributeValue("EmployeeSignature", Convert.ToBase64String(value));
        } else {
            var attribute = this.m_TimeEntries.Root.Attribute("EmployeeApprovalDate");
            if (attribute != null)
                attribute.Remove();
        }
        this.OnPropertyChanged("EmployeeSignature");
    }
}

[IgnoreDataMember]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Computed)]
public Guid? ManagerID {
    get {
        var attribute = this.m_TimeEntries.Root.Attribute("ManagerID");
        if (attribute != null)
            return (Guid)attribute;
        return null;
    }
    set {

        if (this.ValidateSignature(TimeCardEmployeeTypeEnum.DivisionManager))
            throw new ArgumentException("Property cannot be changed once the division manager signature has been set.", "ManagerID");

        if (value.HasValue) {
            if (value.Value == Guid.Empty)
                throw new ArgumentNullException("ManagerID");
            this.m_TimeEntries.Root.SetAttributeValue("ManagerID", value);
        } else {
            var attribute = this.m_TimeEntries.Root.Attribute("ManagerID");
            if (attribute != null)
                attribute.Remove();
        }
        this.OnPropertyChanged("ManagerID");
    }
}

public virtual EmployeeRecord Manager { get; set; }

[NotMapped]
[IgnoreDataMember]
public DateTime? ManagerApprovalDate {
    get {
        var attribute = this.m_TimeEntries.Root.Attribute("ManagerApprovalDate");
        if (attribute != null)
            return (DateTime)attribute;
        return null;
    }
    set {

        if (this.ValidateSignature(TimeCardEmployeeTypeEnum.DivisionManager))
            throw new ArgumentException("Property cannot be changed once the division manager signature has been set.", "ManagerApprovalDate");

        if (value.HasValue)
            this.m_TimeEntries.Root.SetAttributeValue("ManagerApprovalDate", value);
        else {
            var attribute = this.m_TimeEntries.Root.Attribute("ManagerApprovalDate");
            if (attribute != null)
                attribute.Remove();
        }
        this.OnPropertyChanged("ManagerApprovalDate");
    }
}

[NotMapped]
[IgnoreDataMember]
public byte[] ManagerSignature {
    get {
        var attribute = this.m_TimeEntries.Root.Attribute("ManagerSignature");
        if (attribute != null)
            return Convert.FromBase64String((string)attribute);
        return null;
    }
    set {

        if (this.ValidateSignature(TimeCardEmployeeTypeEnum.DivisionManager))
            throw new ArgumentException("Property cannot be changed once the division manager signature has been set.", "ManagerSignature");

        if (value != null) {
            if (value.Length > 1024)
                throw new ArgumentException("Signature cannot be larger than 1KB.", "ManagerSignature");
            this.m_TimeEntries.Root.SetAttributeValue("ManagerSignature", Convert.ToBase64String(value));
        } else {
            var attribute = this.m_TimeEntries.Root.Attribute("ManagerSignature");
            if (attribute != null)
                attribute.Remove();
        }
        this.OnPropertyChanged("ManagerSignature");
    }
}

[IgnoreDataMember]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Computed)]
public Guid? DivisionManagerID {
    get {
        var attribute = this.m_TimeEntries.Root.Attribute("DivisionManagerID");
        if (attribute != null)
            return (Guid)attribute;
        return null;
    }
    set {
        if (value.HasValue) {
            if (value.Value == Guid.Empty)
                throw new ArgumentNullException("DivisionManagerID");
            this.m_TimeEntries.Root.SetAttributeValue("DivisionManagerID", value);
        } else {
            var attribute = this.m_TimeEntries.Root.Attribute("DivisionManagerID");
            if (attribute != null)
                attribute.Remove();
        }
        this.OnPropertyChanged("DivisionManagerID");
    }
}

public virtual EmployeeRecord DivisionManager { get; set; }

[NotMapped]
[IgnoreDataMember]
public DateTime? DivisionManagerApprovalDate {
    get {
        var attribute = this.m_TimeEntries.Root.Attribute("DivisionManagerApprovalDate");
        if (attribute != null)
            return (DateTime)attribute;
        return null;
    }
    set {
        if (value.HasValue)
            this.m_TimeEntries.Root.SetAttributeValue("DivisionManagerApprovalDate", value);
        else {
            var attribute = this.m_TimeEntries.Root.Attribute("DivisionManagerApprovalDate");
            if (attribute != null)
                attribute.Remove();
        }
        this.OnPropertyChanged("DivisionManagerApprovalDate");
    }
}

[NotMapped]
[IgnoreDataMember]
public byte[] DivisionManagerSignature {
    get {
        var attribute = this.m_TimeEntries.Root.Attribute("DivisionManagerSignature");
        if (attribute != null)
            return Convert.FromBase64String((string)attribute);
        return null;
    }
    set {
        if (value != null) {
            if (value.Length > 1024)
                throw new ArgumentException("Signature cannot be larger than 1KB.", "DivisionManagerSignature");
            this.m_TimeEntries.Root.SetAttributeValue("DivisionManagerSignature", Convert.ToBase64String(value));
        } else {
            var attribute = this.m_TimeEntries.Root.Attribute("DivisionManagerSignature");
            if (attribute != null)
                attribute.Remove();
        }
        this.OnPropertyChanged("DivisionManagerSignature");
    }
}

#endregion
}

EF正试图在数据库中声明
Employee_ID
,因为它需要列作为
Employee
表的外键。它不能将您的
EmployeeID
属性及其列用作外键,因为它被声明为computed-EF中的外键不能声明为computed或identity(不支持)


针对您的模型的解决方案要么需要放弃导航属性,只使用ID(并手动加载相关员工),要么放弃这些计算列——我可以想象这两个选项可能都很烦人。

那么如何“放弃”导航属性呢?不清楚如何做到这一点。我正在寻找的是EF停止声明此员工ID。我将手动填写我的导航属性。有什么建议吗?试着把
NotMapped
放在那些导航属性上。拉迪斯拉夫:我试过了,结果导致了其他问题。我找到了一个解决这个问题的方法。现在,我在模型上设置了一个标志,使所有3个Guid属性都返回null。当这种情况发生时,EF将忽略它,并且不再抛出“ReferentialConstraint”异常。我不喜欢这个解决方案,但它现在起作用了。
    public sealed class DatabaseContext : DbContext {

    public DatabaseContext(bool autoDetectChangesEnabled = false, bool lazyLoadingEnabled = false, bool proxyCreationEnabled = false, bool validateOnSaveEnabled = false) {

        this.Configuration.AutoDetectChangesEnabled = autoDetectChangesEnabled;
        this.Configuration.LazyLoadingEnabled = lazyLoadingEnabled;
        this.Configuration.ProxyCreationEnabled = proxyCreationEnabled;
        this.Configuration.ValidateOnSaveEnabled = validateOnSaveEnabled;
    }

    public DbSet<EmployeeRecord> EmployeeRecords { get; set; }

    public DbSet<TimeCardEntry> TimeCards { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {

        modelBuilder.Conventions.Remove<System.Data.Entity.Infrastructure.IncludeMetadataConvention>();
    }
}
exec sp_executesql N'SELECT 
[Limit1].[C1] AS [C1], 
[Limit1].[ID] AS [ID], 
[Limit1].[TimeEntriesXml] AS [TimeEntriesXml], 
[Limit1].[ManagerID] AS [ManagerID], 
[Limit1].[DivisionManagerID] AS [DivisionManagerID], 
[Limit1].[CreatedBy] AS [CreatedBy], 
[Limit1].[Created] AS [Created], 
[Limit1].[UpdatedBy] AS [UpdatedBy], 
[Limit1].[Updated] AS [Updated], 
[Limit1].[Employee_ID] AS [Employee_ID]
FROM ( SELECT TOP (2) 
    [Extent1].[ID] AS [ID], 
    [Extent1].[TimeEntriesXml] AS [TimeEntriesXml], 
    [Extent1].[ManagerID] AS [ManagerID], 
    [Extent1].[DivisionManagerID] AS [DivisionManagerID], 
    [Extent1].[CreatedBy] AS [CreatedBy], 
    [Extent1].[Created] AS [Created], 
    [Extent1].[UpdatedBy] AS [UpdatedBy], 
    [Extent1].[Updated] AS [Updated], 
    [Extent1].[Employee_ID] AS [Employee_ID], 
    1 AS [C1]
    FROM [TimeCard].[TimeCardEntry] AS [Extent1]
    WHERE [Extent1].[ID] = @p0
)  AS [Limit1]',N'@p0 uniqueidentifier',@p0='10F3E723-4E12-48CD-8750-5922A1E42AA3'