EF 4.4防止AutoGen导航属性和/或关系

时间:2013-02-18 17:02:33

标签: entity-framework entity-framework-4

我使用EF启动了一个db模式,并且在尝试手动修改CLR和/或db表时遇到了多个问题。首先是EF放在表格中的“Employee_ID”列。我删除了它,dbo.EdmMetaData和dbo .__ MigrationHistory表,并在发生的运行时错误中摸索着。 现在,我正在努力解决以下错误:

ReferentialConstraint中的依赖属性映射到存储生成的列。专栏:'EmployeeID'。

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

目标)我不想要EF自动映射这3列。由于EF提供的复杂性,我打算自己填写,但我不能告诉EF停止创建导航关系和/或参考约束。

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

第2点)我有一个TimeCardEntity表,它有3个计算列,名为EmployeeID,ManagerID,DivisionManagerID,它们与EmployeeRecord相关。所有都是NULL声明,但显然需要EmployeeID,因为你没有时间卡而没有声明员工。 ManagerID和DivisionManagerID稍后填写。

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

第4点)我有3个存储函数,名为fxGetEmployeeID(xml),fxGetManagerID(xml)和getDivisonManagerID(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
}

这是数据库上下文声明

    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>();
    }
}

更新 我必须添加另一个观察到的EF行为。当我将“NotMappedAttribute”添加到TimeCardEntry的EmployeeID列时,我遇到了另一个问题。 EF将“Employee_ID”列添加回自动生成模式。请参阅下面的TSQL配置文件跟踪:

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'

1 个答案:

答案 0 :(得分:0)

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

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