代码之家  ›  专栏  ›  技术社区  ›  Glory Raj

试图将内容从一个项目复制到另一个项目

  •  0
  • Glory Raj  · 技术社区  · 6 年前

    我有这样的项目实体结构,包括项目名称和项目编号,以及一些列表对象和属性。

    public class DesignProject
    {
        [Key, GraphQLNonNullType]
        public string ProjectNumber { get; set; }
        public string Name { get; set; }
        [Column(TypeName = "jsonb")]
        public ProjectSectionStatus SectionStatuses { get; set; } = new ProjectSectionStatus();
        [ForeignKey("AshraeClimateZone"), GraphQLIgnore]
        public Guid? AshraeClimateZoneId { get; set; }
        public virtual AshraeClimateZone AshraeClimateZone { get; set; }
        [Column(TypeName = "jsonb")]
        public List<ProjectObject<classA>> classAList{ get; set; } = new List<ProjectObject<classA>>();
        [Column(TypeName = "jsonb")]
        public List<ProjectObject<classB>> classBList{ get; set; } = new List<ProjectObject<classB>>();
        ...... 
        ......
        ......
       Some more json columns
    } 
    

    以及 project object 这样的班级

    public class ProjectObject<T>
    {
        public Guid? Id { get; set; }
        public T OriginalObject { get; set; }
        public T ModifiedObject { get; set; }
    
        [GraphQLIgnore, JsonIgnore]
        public T TargetObject
        {
            get
            {
                return ModifiedObject ?? OriginalObject;
            }
        }
    }
    

    ClassA 实体结构如下

    public class ClassA
    {
        public string Edition { get; set; }
        public string City { get; set; }  
    }
    

    我也有一些类似的儿童实体( A级 )与上述相同,我想将内容和状态从一个项目实体复制到另一个项目主体。

    我有项目实体 ProjectNumber 1212,还有一个项目的项目编号为23323,所以我想从以下位置复制整个项目内容 1212 23323 。那么,有什么方法可以用我正在使用的C#来实现这一点吗。具有实体框架核心的Net Core。

    这里,我要复制的源设计项目与目标设计项目具有相同的结构,我可以覆盖目标项目值,我不想在这里更新项目编号。

    有人能告诉我如何实现这个复制吗?提前感谢!!

    如果我需要为这个问题添加任何细节,请告诉我

    更新 :深度复制相关代码

       public InsertResponse<string> CopyBookmarkproject(string SourceProjectNumber, string destinationProjectNumber)
       {
            var sourceDesignProject = this._dbContext.DesignProject.Where(a => a.ProjectNumber == SourceProjectNumber).SingleOrDefault();
            var destinationProject = this._dbContext.DesignProject.Where(a => a.ProjectNumber == destinationProjectNumber).SingleOrDefault();
    
            CopyProject(sourceDesignProject, destinationProject);
    
           // Need to update the Db context at here after deep copy
        }
    
        private void CopyProject(DesignProject sourceDesignProject, DesignProject destinationProject)
        {
            destinationProject.classAList= sourceDesignProject.classAList; // Not sure whether this copy will works 
            destinationProject.AshraeClimateZone = sourceDesignProject.AshraeClimateZone; // not sure whether this copy will works also 
        }
    

    更新的解决方案2:

        var sourceDesignProject = this._dbContext.DesignProjects.AsNoTracking()
                                                        .Where(a => a.ProjectNumber == sourceProjectNumber)
                                                        .Include(a => a.PrimaryBuildingType)
                                                        .Include(a => a.AshraeClimateZone).SingleOrDefault();
    
         var targetDesignProject = this._dbContext.DesignProjects.Where(a => a.ProjectNumber == targetProjectNumber).SingleOrDefault();
    
         sourceDesignProject.ProjectNumber = targetDesignProject.ProjectNumber;
         sourceDesignProject.SectionStatuses.AirSystemsSectionStatus = Entities.Enums.ProjectSectionStage.INCOMPLETE;
                
         sourceDesignProject.SectionStatuses.CodesAndGuidelinesSectionStatus = Entities.Enums.ProjectSectionStage.INCOMPLETE;
         sourceDesignProject.SectionStatuses.ExecutiveSummarySectionStatus = Entities.Enums.ProjectSectionStage.INCOMPLETE;
         sourceDesignProject.SectionStatuses.ExhaustEquipmentSectionStatus = Entities.Enums.ProjectSectionStage.INCOMPLETE;
         sourceDesignProject.SectionStatuses.InfiltrationSectionStatus = Entities.Enums.ProjectSectionStage.INCOMPLETE;
          
    
         this._dbContext.Entry(sourceDesignProject).State = EntityState.Modified; // getting the below error at this line
         this._dbContext.SaveChanges(); 
         ok = true;
    

    出现如下错误

    The instance of entity type 'DesignProject' cannot be tracked because another instance with the same key value for {'ProjectNumber'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

    0 回复  |  直到 6 年前
        1
  •  1
  •   Amirhossein Mehrvarzi GGregson    6 年前

    有一个简单而简短的解决方案,它使用 .AsNoTracking() 对于源条目,分配目标 ProjectNumber 到源,然后更改 EntityState 作为 Modified 它将把所有属性复制到目标条目:

    var sourceDesignProject = this._dbContext.DesignProject.AsNoTracking().Where(a => a.ProjectNumber == SourceProjectNumber).SingleOrDefault();
    var destinationProject = this._dbContext.DesignProject.Where(a => a.ProjectNumber == destinationProjectNumber).SingleOrDefault();
    
    sourceDesignProject.ProjectNumber = destinationProject.ProjectNumber;
    this._dbContext.Entry(sourceDesignProject).State = System.Data.Entity.EntityState.Modified;
    this._dbContext.SaveChanges();
    

    确保 您的关系属性之前已加载。

        2
  •  0
  •   Kiran Thokal    6 年前

    你可以使用反射。由于您同时拥有源对象和目标对象,因此它们属于同一类型。您可以遍历源对象,获取属性并替换值。 类似于:

    if (inputObjectA != null && inputObjectB != null)
    {
        //create variables to store object values
        object value1, value2;
     
        PropertyInfo[] properties = inputObjectA.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
         
        //get all public properties of the object using reflection  
        foreach (PropertyInfo propertyInfo in properties)
        {
        //get the property values of both the objects
          value1 = propertyInfo.GetValue(inputObjectA, null);
          value2 = propertyInfo.GetValue(inputObjectB, null);
        }
    

    忽略不需要复制的属性。该方法将具有如下签名:

    CopyObjects(object inputObjectA, object inputObjectB, string[] ignorePropertiesList)
    
        3
  •  0
  •   Arman Ebrahimpour jacek    6 年前

    对于对象的深度复制,有两种选择:

    1-使用 BinaryFormatter (需求 Serializable 你的类的属性, See original answer ):

    public static T DeepClone<T>(this T obj)
    {
        using (var ms = new MemoryStream())
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(ms, obj);
            ms.Position = 0;
    
            return (T) formatter.Deserialize(ms);
        }
    }
    

    2-使用 JsonSerializers 比如NewtoneSoft:

    public static T CloneJson<T>(this T source)
    {            
        // Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(source, null))
        {
            return default(T);
        }
    
        // initialize inner objects individually
        // for example in default constructor some list property initialized with some values,
        // but in 'source' these items are cleaned -
        // without ObjectCreationHandling.Replace default constructor values will be added to result
        var deserializeSettings = new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace};
    
        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
    }
    

    更新

    以下是您可以使用的代码 NewtonSoft Json 图书馆:

    private void CopyProject(DesignProject sourceDesignProject, ref DesignProject destinationProject)
    {
        if (Object.ReferenceEquals(sourceDesignProject, null))
        {
            destinationProject = null;
            return;
        }
    
        var deserializeSettings = new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace};
    
        var destProjNumber = destinationProject.ProjectNumber;
    
        destinationProject = JsonConvert.DeserializeObject<DesignProject>
            (JsonConvert.SerializeObject(sourceDesignProject), deserializeSettings);
    
        destinationProject.ProjectNumber = destProjNumber;
    }
    
        4
  •  0
  •   Noldor    6 年前

    我总是更喜欢使用 AutoMapper 对于这类工作。它经过优化,犯错误的风险更低。而且比序列化/反序列化方法更好,因为这会导致性能问题。

    在构造函数中(或在startup.cs中并通过依赖注入传递)

    var config = new MapperConfiguration(cfg => { 
                     cfg.CreateMap<DesignProject, DesignProject>().ForMember(x => x.Id, opt => opt.Ignore());
                     cfg.CreateMap<ProjectObject<ClassA>, ProjectObject<ClassA>>().ForMember(x => x.Id, opt => opt.Ignore()));
                     cfg.CreateMap<ProjectObject<ClassA>, ProjectObject<ClassB>>().ForMember(x => x.Id, opt => opt.Ignore()));
                     cfg.CreateMap<ProjectObject<ClassB>, ProjectObject<ClassB>>().ForMember(x => x.Id, opt => opt.Ignore()));
                     cfg.CreateMap<ProjectObject<ClassB>, ProjectObject<ClassA>>().ForMember(x => x.Id, opt => opt.Ignore()));
    
     });
     var mapper = config.CreateMapper();
    

    在您的方法中:

     var newProject = mapper.Map(sourceProject, new DesignProject());
    

     mapper.Map(sourceProject, targetProject);
    
        5
  •  -1
  •   Lazar Đorđević    6 年前

    这不应该起作用。若我理解你们想将列表中的所有元素复制到新列表中,但要创建新对象。然后,您可以使用扩展方法克隆完整列表,如下所述 link 。要更新导航属性,请查看此帖子 link .