1

我正在使用Entity Framework,RIA Services和MVVM-Light工具包创建Silverlight 4应用程序。 > *资源 使用RIA服务插入/更新组合属性

  • 作业1 - - > *工作计划
  • 工作计划1 - > * WorkplanItems
  • 资源1​​

    • 伯1:用一个复杂的对象图,包含下面的结构的应用程序处理 - > *分配
    • WorkplanItems 1 - > *分配

    我希望能够(使用包含属性/指令)来加载工作,这个工作精细。从特定作业的根加载完整图形。然而,当我更改提交回,我得到一个错误

    Entity for operation '0' has multiple parents 
    

    它已经从this post我的理解是,在我的元数据组成的属性是什么应该允许我提出这是一个完整的图形,然后处理更新的服务器上的所有对象正确地从我的Silverlight应用程序进行一次往返。我的目标是不要在每次更改时提交更改,但要允许用户对作业进行一系列更改,并将其与相关部分进行更改,然后提交或取消更改。

    请让我知道,如果你知道我忽略了这个问题吗?这里是我设置的元数据:

    // The MetadataTypeAttribute identifies AssignmentMetadata as the class 
    // that carries additional metadata for the Assignment class. 
    [MetadataTypeAttribute(typeof(Assignment.AssignmentMetadata))] 
    public partial class Assignment 
    { 
    
        // This class allows you to attach custom attributes to properties 
        // of the Assignment class. 
        // 
        // For example, the following marks the Xyz property as a 
        // required property and specifies the format for valid values: 
        // [Required] 
        // [RegularExpression("[A-Z][A-Za-z0-9]*")] 
        // [StringLength(32)] 
        // public string Xyz { get; set; } 
        internal sealed class AssignmentMetadata 
        { 
    
         // Metadata classes are not meant to be instantiated. 
         private AssignmentMetadata() 
         { 
         } 
    
         public decimal CostBudgeted { get; set; } 
    
         public decimal CostRemaining { get; set; } 
    
         public decimal HoursBudgeted { get; set; } 
    
         public decimal HoursRemaining { get; set; } 
    
         public bool IsComplete { get; set; } 
    
         public int ItemID { get; set; } 
    
         public Job Job { get; set; } 
    
         public int JobID { get; set; } 
    
         public Resource Resource { get; set; } 
    
         public int ResourceID { get; set; } 
    
         public Workplan Workplan { get; set; } 
    
         public int WorkplanID { get; set; } 
    
         public WorkplanItem WorkplanItem { get; set; } 
        } 
    } 
    
    // The MetadataTypeAttribute identifies JobMetadata as the class 
    // that carries additional metadata for the Job class. 
    [MetadataTypeAttribute(typeof(Job.JobMetadata))] 
    public partial class Job 
    { 
    
        // This class allows you to attach custom attributes to properties 
        // of the Job class. 
        // 
        // For example, the following marks the Xyz property as a 
        // required property and specifies the format for valid values: 
        // [Required] 
        // [RegularExpression("[A-Z][A-Za-z0-9]*")] 
        // [StringLength(32)] 
        // public string Xyz { get; set; } 
        internal sealed class JobMetadata 
        { 
    
         // Metadata classes are not meant to be instantiated. 
         private JobMetadata() 
         { 
         } 
    
         [Display(AutoGenerateField = false)] 
         [Include] 
         [Composition] 
         public EntityCollection<Assignment> Assignments { get; set; } 
    
         [Display(Name="Client Job", Order=2, Description="Is this a client job?")] 
         [DefaultValue(true)] 
         public bool IsRealJob { get; set; } 
    
         [Display(AutoGenerateField = false)] 
         [Include] 
         public JobDetail JobDetail { get; set; } 
    
         [Display(AutoGenerateField = false)] 
         public int JoblID { get; set; } 
    
         [Display(Name="Job Title", Order=1, Description="What should this job be called?")] 
         public string Title { get; set; } 
    
         [Display(AutoGenerateField = false)] 
         [Include] 
         [Composition] 
         public EntityCollection<WorkplanItem> WorkplanItems { get; set; } 
    
         [Display(AutoGenerateField = false)] 
         [Include] 
         [Composition] 
         public EntityCollection<Workplan> Workplans { get; set; } 
    
    
         [Display(AutoGenerateField = false)] 
         [Include] 
         [Composition] 
         public EntityCollection<Resource> Resources { get; set; } 
        } 
    } 
    
    // The MetadataTypeAttribute identifies JobDetailMetadata as the class 
    // that carries additional metadata for the JobDetail class. 
    [MetadataTypeAttribute(typeof(JobDetail.JobDetailMetadata))] 
    public partial class JobDetail 
    { 
    
        // This class allows you to attach custom attributes to properties 
        // of the JobDetail class. 
        // 
        // For example, the following marks the Xyz property as a 
        // required property and specifies the format for valid values: 
        // [Required] 
        // [RegularExpression("[A-Z][A-Za-z0-9]*")] 
        // [StringLength(32)] 
        // public string Xyz { get; set; } 
        internal sealed class JobDetailMetadata 
        { 
    
         // Metadata classes are not meant to be instantiated. 
         private JobDetailMetadata() 
         { 
         } 
    
         [Display(Name="Client", Order=1,Description="Name of the Client")] 
         public string Client { get; set; } 
    
         [Display(Name = "Client Fee", Order = 5, Description = "Client Fee from Engagement Letter")] 
         [DisplayFormat(DataFormatString="C",NullDisplayText="<Not Set>",ApplyFormatInEditMode=true)] 
         public Nullable<decimal> ClientFee { get; set; } 
    
         [Display(AutoGenerateField=false)] 
         public int ClientIndex { get; set; } 
    
         [Display(AutoGenerateField = true)] 
         public string EFOLDERID { get; set; } 
    
         [Display(Name = "Engagement Name", Order = 4, Description = "Friendly name of the Engagement")] 
         public string Engagement { get; set; } 
    
         [Display(Name = "Eng Type", Order = 3, Description = "Type of Work being done")] 
         public string EngagementType { get; set; } 
    
         [Display(AutoGenerateField = false)] 
         public Job Job { get; set; } 
    
         [Display(AutoGenerateField = false)] 
         public int JobID { get; set; } 
    
         [Display(AutoGenerateField = false)] 
         public int PEJobID { get; set; } 
    
         [Display(Name = "Service", Order = 2, Description = "Service Type")] 
         public string Service { get; set; } 
    
         [Display(Name = "Timing of the Work", Order = 6, Description = "When will this work occur?")] 
         public string Timing { get; set; } 
        } 
    } 
    
    // The MetadataTypeAttribute identifies PendingTimesheetMetadata as the class 
    // that carries additional metadata for the PendingTimesheet class. 
    [MetadataTypeAttribute(typeof(PendingTimesheet.PendingTimesheetMetadata))] 
    public partial class PendingTimesheet 
    { 
    
        // This class allows you to attach custom attributes to properties 
        // of the PendingTimesheet class. 
        // 
        // For example, the following marks the Xyz property as a 
        // required property and specifies the format for valid values: 
        // [Required] 
        // [RegularExpression("[A-Z][A-Za-z0-9]*")] 
        // [StringLength(32)] 
        // public string Xyz { get; set; } 
        internal sealed class PendingTimesheetMetadata 
        { 
    
         // Metadata classes are not meant to be instantiated. 
         private PendingTimesheetMetadata() 
         { 
         } 
    
         public decimal PendingHours { get; set; } 
    
         public string UserName { get; set; } 
    
         public DateTime WorkDate { get; set; } 
    
         [Include] 
         public Workplan Workplan { get; set; } 
    
         public int WorkplanID { get; set; } 
        } 
    } 
    
    // The MetadataTypeAttribute identifies ResourceMetadata as the class 
    // that carries additional metadata for the Resource class. 
    [MetadataTypeAttribute(typeof(Resource.ResourceMetadata))] 
    public partial class Resource 
    { 
    
        // This class allows you to attach custom attributes to properties 
        // of the Resource class. 
        // 
        // For example, the following marks the Xyz property as a 
        // required property and specifies the format for valid values: 
        // [Required] 
        // [RegularExpression("[A-Z][A-Za-z0-9]*")] 
        // [StringLength(32)] 
        // public string Xyz { get; set; } 
        internal sealed class ResourceMetadata 
        { 
    
         // Metadata classes are not meant to be instantiated. 
         private ResourceMetadata() 
         { 
         } 
    
         [Include] 
         [Composition] 
         public EntityCollection<Assignment> Assignments { get; set; } 
    
         [Include] 
         public Job Job { get; set; } 
    
         public int JobID { get; set; } 
    
         public decimal Rate { get; set; } 
    
         public int ResourceID { get; set; } 
    
         public string Title { get; set; } 
    
         public string UserName { get; set; } 
        } 
    } 
    
    // The MetadataTypeAttribute identifies WorkplanMetadata as the class 
    // that carries additional metadata for the Workplan class. 
    [MetadataTypeAttribute(typeof(Workplan.WorkplanMetadata))] 
    public partial class Workplan 
    { 
    
        // This class allows you to attach custom attributes to properties 
        // of the Workplan class. 
        // 
        // For example, the following marks the Xyz property as a 
        // required property and specifies the format for valid values: 
        // [Required] 
        // [RegularExpression("[A-Z][A-Za-z0-9]*")] 
        // [StringLength(32)] 
        // public string Xyz { get; set; } 
        internal sealed class WorkplanMetadata 
        { 
    
         // Metadata classes are not meant to be instantiated. 
         private WorkplanMetadata() 
         { 
         } 
    
         [Include] 
         [Composition] 
         public EntityCollection<Assignment> Assignments { get; set; } 
    
         public string Description { get; set; } 
    
         [Include] 
         public Job Job { get; set; } 
    
         public int JobID { get; set; } 
    
         public EntityCollection<PendingTimesheet> PendingTimesheets { get; set; } 
    
         public Nullable<int> PETaskID { get; set; } 
    
         public decimal TtlCost { get; set; } 
    
         public decimal TtlHours { get; set; } 
    
         public DateTime WorkEnd { get; set; } 
    
         public int WorkplanID { get; set; } 
    
         [Include] 
         [Composition] 
         public EntityCollection<WorkplanItem> WorkplanItems { get; set; } 
    
         public DateTime WorkStart { get; set; } 
        } 
    } 
    
    // The MetadataTypeAttribute identifies WorkplanItemMetadata as the class 
    // that carries additional metadata for the WorkplanItem class. 
    [MetadataTypeAttribute(typeof(WorkplanItem.WorkplanItemMetadata))] 
    public partial class WorkplanItem 
    { 
    
        // This class allows you to attach custom attributes to properties 
        // of the WorkplanItem class. 
        // 
        // For example, the following marks the Xyz property as a 
        // required property and specifies the format for valid values: 
        // [Required] 
        // [RegularExpression("[A-Z][A-Za-z0-9]*")] 
        // [StringLength(32)] 
        // public string Xyz { get; set; } 
        internal sealed class WorkplanItemMetadata 
        { 
    
         // Metadata classes are not meant to be instantiated. 
         private WorkplanItemMetadata() 
         { 
         } 
    
         [Include] 
         [Composition] 
         public EntityCollection<Assignment> Assignments { get; set; } 
    
         public string Description { get; set; } 
    
         public int ItemID { get; set; } 
    
         [Include] 
         public Job Job { get; set; } 
    
         public int JobID { get; set; } 
    
         public string Notes { get; set; } 
    
         public short Ordinal { get; set; } 
    
         [Include] 
         public Workplan Workplan { get; set; } 
    
         public int WorkplanID { get; set; } 
        } 
    } 
    
  • 回答

    2

    我已经想出了解决我的问题。这实际上是真正强大的,一旦你了解一些内部的工作和需要注意的地方:

    1. 只有[组成]和[包含]属性应用到你的对象图的根。
    2. 组合的根对象是提交的内容,并且是更新过程开始的位置。
    3. 您的根对象的EntityState实际上可能不代表更新(就像我的情况)。
    4. 什么都先重新重视你的图形,所有对象得到重视和他们的状态被设定为相同的值(插入,更新,删除等)
    5. 您的图表后重新连接你需要更新每个实体根据提交的ChangeSet。

    可能还有更多的我还没有完全理解;但是,这在我的环境中起作用。我想找出一个更好的方法来做到这一点,但当我尝试应用通用附加方法时,我似乎遇到了不同的问题。

    以下是我想出了我的更新方法:

    public void UpdateJob(Job currentJob) 
        { 
         //this.ObjectContext.Jobs.AttachAsModified(currentJob, this.ChangeSet.GetOriginal(currentJob)); 
    
         // compositional update process 
         foreach (Assignment a in this.ChangeSet.GetAssociatedChanges(currentJob, j => j.Assignments)) 
         { 
          ChangeOperation op = this.ChangeSet.GetChangeOperation(a); 
          switch (op) 
          { 
           case ChangeOperation.Insert: 
            InsertAssignment(a); 
            break; 
           case ChangeOperation.Update: 
            UpdateAssignment(a); 
            break; 
           case ChangeOperation.Delete: 
            DeleteAssignment(a); 
            break; 
           case ChangeOperation.None: 
            if (a.EntityState == EntityState.Detached) 
             this.ObjectContext.Assignments.Attach(a); 
            System.Data.Objects.ObjectStateEntry ose; 
            if (this.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(a.EntityKey, out ose)) 
             this.ObjectContext.ObjectStateManager.ChangeObjectState(a, EntityState.Unchanged); 
            break; 
          } 
         } 
    
         foreach (WorkplanItem wpi in this.ChangeSet.GetAssociatedChanges(currentJob, j => j.WorkplanItems)) 
         { 
          ChangeOperation op = this.ChangeSet.GetChangeOperation(wpi); 
          switch (op) 
          { 
           case ChangeOperation.Insert: 
            InsertWorkplanItem(wpi); 
            break; 
           case ChangeOperation.Update: 
            UpdateWorkplanItem(wpi); 
            break; 
           case ChangeOperation.Delete: 
            DeleteWorkplanItem(wpi); 
            break; 
           case ChangeOperation.None: 
            if (wpi.EntityState == EntityState.Detached) 
             this.ObjectContext.WorkplanItems.Attach(wpi); 
            System.Data.Objects.ObjectStateEntry ose; 
            if (this.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(wpi.EntityKey, out ose)) 
             this.ObjectContext.ObjectStateManager.ChangeObjectState(wpi, EntityState.Unchanged); 
            break; 
          } 
         } 
    
         foreach (Workplan wp in this.ChangeSet.GetAssociatedChanges(currentJob, j => j.Workplans)) 
         { 
          ChangeOperation op = this.ChangeSet.GetChangeOperation(wp); 
          switch (op) 
          { 
           case ChangeOperation.Insert: 
            InsertWorkplan(wp); 
            break; 
           case ChangeOperation.Update: 
            UpdateWorkplan(wp); 
            break; 
           case ChangeOperation.Delete: 
            DeleteWorkplan(wp); 
            break; 
           case ChangeOperation.None: 
            if (wp.EntityState == EntityState.Detached) 
             this.ObjectContext.Workplans.Attach(wp); 
            System.Data.Objects.ObjectStateEntry ose; 
            if (this.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(wp.EntityKey, out ose)) 
             this.ObjectContext.ObjectStateManager.ChangeObjectState(wp, EntityState.Unchanged); 
            break; 
          } 
         } 
    
         foreach (Resource res in this.ChangeSet.GetAssociatedChanges(currentJob, j => j.Resources)) 
         { 
          ChangeOperation op = this.ChangeSet.GetChangeOperation(res); 
          switch (op) 
          { 
           case ChangeOperation.Insert: 
            InsertResource(res); 
            break; 
           case ChangeOperation.Update: 
            UpdateResource(res); 
            break; 
           case ChangeOperation.Delete: 
            DeleteResource(res); 
            break; 
           case ChangeOperation.None: 
            if (res.EntityState == EntityState.Detached) 
             this.ObjectContext.Resources.Attach(res); 
            System.Data.Objects.ObjectStateEntry ose; 
            if (this.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(res.EntityKey, out ose)) 
             this.ObjectContext.ObjectStateManager.ChangeObjectState(res, EntityState.Unchanged); 
            break; 
          } 
         } 
    
         ChangeOperation detailop = this.ChangeSet.GetChangeOperation(currentJob.JobDetail); 
         switch (detailop) 
         { 
          case ChangeOperation.Insert: 
           InsertJobDetail(currentJob.JobDetail); 
           break; 
          case ChangeOperation.Update: 
           UpdateJobDetail(currentJob.JobDetail); 
           break; 
          case ChangeOperation.Delete: 
           DeleteJobDetail(currentJob.JobDetail); 
           break; 
          case ChangeOperation.None: 
           System.Data.Objects.ObjectStateEntry ose; 
           if (this.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(currentJob.JobDetail.EntityKey, out ose)) 
             this.ObjectContext.ObjectStateManager.ChangeObjectState(currentJob.JobDetail, EntityState.Unchanged); 
           break; 
         } 
    
         if (currentJob.EntityState == EntityState.Detached) 
          this.ObjectContext.Jobs.Attach(currentJob); 
    
         ChangeOperation jobop = this.ChangeSet.GetChangeOperation(currentJob); 
         switch (jobop) 
         { 
          case ChangeOperation.Insert: 
           InsertJob(currentJob); 
           break; 
          case ChangeOperation.Update: 
           // Since this is the compositional root, we need to make sure there really is a change 
           var origJob = this.ChangeSet.GetOriginal(currentJob); 
           if (origJob != null) 
           { 
            this.ObjectContext.Jobs.AttachAsModified(currentJob, 
             origJob); 
           } 
           else 
           { 
            this.ObjectContext.ObjectStateManager.ChangeObjectState(
             currentJob, EntityState.Unchanged); 
           } 
           break; 
          case ChangeOperation.Delete: 
           DeleteJob(currentJob); 
           break; 
          case ChangeOperation.None: 
           this.ObjectContext.ObjectStateManager.ChangeObjectState(currentJob, EntityState.Unchanged); 
           break; 
         } 
    
        } 
    

    此外,这里的变化,我不得不做出的元数据类为我的实体。

    // The MetadataTypeAttribute identifies AssignmentMetadata as the class 
    // that carries additional metadata for the Assignment class. 
    [MetadataTypeAttribute(typeof(Assignment.AssignmentMetadata))] 
    public partial class Assignment 
    { 
    
        // This class allows you to attach custom attributes to properties 
        // of the Assignment class. 
        // 
        // For example, the following marks the Xyz property as a 
        // required property and specifies the format for valid values: 
        // [Required] 
        // [RegularExpression("[A-Z][A-Za-z0-9]*")] 
        // [StringLength(32)] 
        // public string Xyz { get; set; } 
        internal sealed class AssignmentMetadata 
        { 
    
         // Metadata classes are not meant to be instantiated. 
         private AssignmentMetadata() 
         { 
         } 
    
         public decimal CostBudgeted { get; set; } 
    
         public decimal CostRemaining { get; set; } 
    
         public decimal HoursBudgeted { get; set; } 
    
         public decimal HoursRemaining { get; set; } 
    
         public bool IsComplete { get; set; } 
    
         public int ItemID { get; set; } 
    
         public Job Job { get; set; } 
    
         public int JobID { get; set; } 
    
         public Resource Resource { get; set; } 
    
         public int ResourceID { get; set; } 
    
         public Workplan Workplan { get; set; } 
    
         public int WorkplanID { get; set; } 
    
         public WorkplanItem WorkplanItem { get; set; } 
        } 
    } 
    
    // The MetadataTypeAttribute identifies JobMetadata as the class 
    // that carries additional metadata for the Job class. 
    [MetadataTypeAttribute(typeof(Job.JobMetadata))] 
    public partial class Job 
    { 
    
        // This class allows you to attach custom attributes to properties 
        // of the Job class. 
        // 
        // For example, the following marks the Xyz property as a 
        // required property and specifies the format for valid values: 
        // [Required] 
        // [RegularExpression("[A-Z][A-Za-z0-9]*")] 
        // [StringLength(32)] 
        // public string Xyz { get; set; } 
        internal sealed class JobMetadata 
        { 
    
         // Metadata classes are not meant to be instantiated. 
         private JobMetadata() 
         { 
         } 
    
         [Display(AutoGenerateField = false)] 
         [Include] 
         [Composition] 
         public EntityCollection<Assignment> Assignments { get; set; } 
    
         [Display(Name="Client Job", Order=2, Description="Is this a client job?")] 
         [DefaultValue(true)] 
         public bool IsRealJob { get; set; } 
    
         [Display(AutoGenerateField = false)] 
         [Include] 
         [Composition] 
         public JobDetail JobDetail { get; set; } 
    
         [Display(AutoGenerateField = false)] 
         public int JoblID { get; set; } 
    
         [Display(Name="Job Title", Order=1, Description="What should this job be called?")] 
         public string Title { get; set; } 
    
         [Display(AutoGenerateField = false)] 
         [Include] 
         [Composition] 
         public EntityCollection<WorkplanItem> WorkplanItems { get; set; } 
    
         [Display(AutoGenerateField = false)] 
         [Include] 
         [Composition] 
         public EntityCollection<Workplan> Workplans { get; set; } 
    
    
         [Display(AutoGenerateField = false)] 
         [Include] 
         [Composition] 
         public EntityCollection<Resource> Resources { get; set; } 
        } 
    } 
    
    // The MetadataTypeAttribute identifies JobDetailMetadata as the class 
    // that carries additional metadata for the JobDetail class. 
    [MetadataTypeAttribute(typeof(JobDetail.JobDetailMetadata))] 
    public partial class JobDetail 
    { 
    
        // This class allows you to attach custom attributes to properties 
        // of the JobDetail class. 
        // 
        // For example, the following marks the Xyz property as a 
        // required property and specifies the format for valid values: 
        // [Required] 
        // [RegularExpression("[A-Z][A-Za-z0-9]*")] 
        // [StringLength(32)] 
        // public string Xyz { get; set; } 
        internal sealed class JobDetailMetadata 
        { 
    
         // Metadata classes are not meant to be instantiated. 
         private JobDetailMetadata() 
         { 
         } 
    
         [Display(Name="Client", Order=1,Description="Name of the Client")] 
         public string Client { get; set; } 
    
         [Display(Name = "Client Fee", Order = 5, Description = "Client Fee from Engagement Letter")] 
         [DisplayFormat(DataFormatString="C",NullDisplayText="<Not Set>",ApplyFormatInEditMode=true)] 
         public Nullable<decimal> ClientFee { get; set; } 
    
         [Display(AutoGenerateField=false)] 
         public int ClientIndex { get; set; } 
    
         [Display(AutoGenerateField = true)] 
         public string EFOLDERID { get; set; } 
    
         [Display(Name = "Engagement Name", Order = 4, Description = "Friendly name of the Engagement")] 
         public string Engagement { get; set; } 
    
         [Display(Name = "Eng Type", Order = 3, Description = "Type of Work being done")] 
         public string EngagementType { get; set; } 
    
         [Display(AutoGenerateField = false)] 
         public Job Job { get; set; } 
    
         [Display(AutoGenerateField = false)] 
         public int JobID { get; set; } 
    
         [Display(AutoGenerateField = false)] 
         public int PEJobID { get; set; } 
    
         [Display(Name = "Service", Order = 2, Description = "Service Type")] 
         public string Service { get; set; } 
    
         [Display(Name = "Timing of the Work", Order = 6, Description = "When will this work occur?")] 
         public string Timing { get; set; } 
        } 
    } 
    
    // The MetadataTypeAttribute identifies PendingTimesheetMetadata as the class 
    // that carries additional metadata for the PendingTimesheet class. 
    [MetadataTypeAttribute(typeof(PendingTimesheet.PendingTimesheetMetadata))] 
    public partial class PendingTimesheet 
    { 
    
        // This class allows you to attach custom attributes to properties 
        // of the PendingTimesheet class. 
        // 
        // For example, the following marks the Xyz property as a 
        // required property and specifies the format for valid values: 
        // [Required] 
        // [RegularExpression("[A-Z][A-Za-z0-9]*")] 
        // [StringLength(32)] 
        // public string Xyz { get; set; } 
        internal sealed class PendingTimesheetMetadata 
        { 
    
         // Metadata classes are not meant to be instantiated. 
         private PendingTimesheetMetadata() 
         { 
         } 
    
         public decimal PendingHours { get; set; } 
    
         public string UserName { get; set; } 
    
         public DateTime WorkDate { get; set; } 
    
         [Include] 
         public Workplan Workplan { get; set; } 
    
         public int WorkplanID { get; set; } 
        } 
    } 
    
    // The MetadataTypeAttribute identifies ResourceMetadata as the class 
    // that carries additional metadata for the Resource class. 
    [MetadataTypeAttribute(typeof(Resource.ResourceMetadata))] 
    public partial class Resource 
    { 
    
        // This class allows you to attach custom attributes to properties 
        // of the Resource class. 
        // 
        // For example, the following marks the Xyz property as a 
        // required property and specifies the format for valid values: 
        // [Required] 
        // [RegularExpression("[A-Z][A-Za-z0-9]*")] 
        // [StringLength(32)] 
        // public string Xyz { get; set; } 
        internal sealed class ResourceMetadata 
        { 
    
         // Metadata classes are not meant to be instantiated. 
         private ResourceMetadata() 
         { 
         } 
    
         public EntityCollection<Assignment> Assignments { get; set; } 
    
         public Job Job { get; set; } 
    
         public int JobID { get; set; } 
    
         public decimal Rate { get; set; } 
    
         public int ResourceID { get; set; } 
    
         public string Title { get; set; } 
    
         public string UserName { get; set; } 
        } 
    } 
    
    // The MetadataTypeAttribute identifies WorkplanMetadata as the class 
    // that carries additional metadata for the Workplan class. 
    [MetadataTypeAttribute(typeof(Workplan.WorkplanMetadata))] 
    public partial class Workplan 
    { 
    
        // This class allows you to attach custom attributes to properties 
        // of the Workplan class. 
        // 
        // For example, the following marks the Xyz property as a 
        // required property and specifies the format for valid values: 
        // [Required] 
        // [RegularExpression("[A-Z][A-Za-z0-9]*")] 
        // [StringLength(32)] 
        // public string Xyz { get; set; } 
        internal sealed class WorkplanMetadata 
        { 
    
         // Metadata classes are not meant to be instantiated. 
         private WorkplanMetadata() 
         { 
         } 
    
         public EntityCollection<Assignment> Assignments { get; set; } 
    
         public string Description { get; set; } 
    
         public Job Job { get; set; } 
    
         public int JobID { get; set; } 
    
         public EntityCollection<PendingTimesheet> PendingTimesheets { get; set; } 
    
         public Nullable<int> PETaskID { get; set; } 
    
         public decimal TtlCost { get; set; } 
    
         public decimal TtlHours { get; set; } 
    
         public DateTime WorkEnd { get; set; } 
    
         public int WorkplanID { get; set; } 
    
         public EntityCollection<WorkplanItem> WorkplanItems { get; set; } 
    
         public DateTime WorkStart { get; set; } 
        } 
    } 
    
    // The MetadataTypeAttribute identifies WorkplanItemMetadata as the class 
    // that carries additional metadata for the WorkplanItem class. 
    [MetadataTypeAttribute(typeof(WorkplanItem.WorkplanItemMetadata))] 
    public partial class WorkplanItem 
    { 
    
        // This class allows you to attach custom attributes to properties 
        // of the WorkplanItem class. 
        // 
        // For example, the following marks the Xyz property as a 
        // required property and specifies the format for valid values: 
        // [Required] 
        // [RegularExpression("[A-Z][A-Za-z0-9]*")] 
        // [StringLength(32)] 
        // public string Xyz { get; set; } 
        internal sealed class WorkplanItemMetadata 
        { 
    
         // Metadata classes are not meant to be instantiated. 
         private WorkplanItemMetadata() 
         { 
         } 
    
         public EntityCollection<Assignment> Assignments { get; set; } 
    
         public string Description { get; set; } 
    
         public int ItemID { get; set; } 
    
         public Job Job { get; set; } 
    
         public int JobID { get; set; } 
    
         public string Notes { get; set; } 
    
         public short Ordinal { get; set; } 
    
         public Workplan Workplan { get; set; } 
    
         public int WorkplanID { get; set; } 
        } 
    } 
    

    如果有人有其他提示/想法,请添加它们。我会继续发布更多,因为我了解更多。