나는이 같은 문제에 대한 해결책을 찾았습니다. 필자는 텍스트 템플릿을 사용하여 상속 변경을 적용하는 매우 효과적인 방법을 얻을 수있었습니다. 여기
이
먼저 데이터베이스를 작성하면 다른 외부 키에 다른 방법으로 상속을 대표하는 외래 키 제약 조건의 이름을 필요 제외하고 정상적으로 데이터베이스를 만드는 방법 ...입니다.
pkPeople - Primary key constraint
fkPersonAddress - Foreign key to the Address table
inInstructorPerson - Foreign key representing inheritance
ckPersonAge - Check constraint
, 당신은 새로운 엔터티 데이터 모델을 만들려면 '데이터'엔티티 모델
다음을 생성하고 생성 :
내가 제약에 사용하는 이름 지정 규칙은이 같은 두 글자의 접두사입니다 데이터베이스에서. 이 EDMX 파일에서 어떤 것도 수정하지 마십시오. 생성 된 그대로 유지해야합니다. 그렇게하면 데이터베이스를 크게 변경해야 할 경우 삭제하고 다시 만들 수 있습니다.
변경해야 할 것은 edmx 파일의 사용자 지정 도구 속성에서 'EntityModelCodeGenerator'를 삭제하는 것입니다.
프로젝트에
그런 다음 새 텍스트 템플릿 (.TT 파일)을 추가 텍스트 템플릿을 추가합니다. 이 텍스트 템플리트의 작업은 이전 단계에서 작성된 XML 기반 edmx 파일을보고 'in'접두어로 시작하는 모든 연관을 찾고 필요에 따라 XML을 조정하여 연관에 의해 참조 된 엔티티를 상속 된 객체.
이렇게하기위한 코드는 다음과 같습니다. 당신이 당신을 위해 작동하기 위해 수행해야하는 유일한 것은 라인에 기본 EDMX 파일의 하드 코딩 된 파일 이름을 변경 (10)
<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".edmx" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
<#
var edmx = XDocument.Load(this.Host.ResolvePath("MyData.edmx"));
var edmxns = edmx.Root.Name.Namespace;
var csdl = edmx.Root.Element(edmxns + "Runtime").Element(edmxns + "ConceptualModels");
var csdlSchema = csdl.Elements().First();
var csdlns = csdlSchema.Name.Namespace;
var modelns = csdlSchema.Attribute("Namespace").Value;
var InheritiedObjects = new List<InheritedObject>();
// GET LIST OF INHERITS
foreach (var a in csdlSchema.Elements(csdlns + "Association").Where(ca => ca.Attribute("Name").Value.StartsWith("in"))) {
InheritedObject io = new InheritedObject() { ForeignKey = a.Attribute("Name").Value };
try {
io.QualifiedParent = a.Elements(csdlns + "End").Single(cae => cae.Attribute("Multiplicity").Value == "1").Attribute("Type").Value;
io.QualifiedChild = a.Elements(csdlns + "End").Single(cae => cae.Attribute("Multiplicity").Value == "0..1").Attribute("Type").Value;
InheritiedObjects.Add(io);
} catch {
Warning("Foreign key '" + io.ForeignKey + "' doesn't contain parent and child roles with the correct multiplicity.");
}
}
// SET ABSTRACT OBJECTS
foreach (var ao in InheritiedObjects.Distinct()) {
WriteLine("<!-- ABSTRACT: {0} -->", ao.Parent);
csdlSchema.Elements(csdlns + "EntityType")
.Single(et => et.Attribute("Name").Value == ao.Parent)
.SetAttributeValue("Abstract", "true");
}
WriteLine("<!-- -->");
// SET INHERITANCE
foreach (var io in InheritiedObjects) {
XElement EntityType = csdlSchema.Elements(csdlns + "EntityType").Single(cet => cet.Attribute("Name").Value == io.Child);
WriteLine("<!-- INHERITED OBJECT: {0} -->", io.Child);
// REMOVE THE ASSOCIATION SET
csdlSchema.Element(csdlns + "EntityContainer")
.Elements(csdlns + "AssociationSet")
.Single(cas => cas.Attribute("Association").Value == modelns + "." + io.ForeignKey)
.Remove();
WriteLine("<!-- ASSOCIATION SET {0} REMOVED -->", modelns + "." + io.ForeignKey);
// REMOVE THE ASSOCIATION
csdlSchema.Elements(csdlns + "Association")
.Single(ca => ca.Attribute("Name").Value == io.ForeignKey)
.Remove();
WriteLine("<!-- ASSOCIATION {0} REMOVED -->", io.ForeignKey);
// GET THE CHILD ENTITY SET NAME
io.ChildSet = csdlSchema.Element(csdlns + "EntityContainer")
.Elements(csdlns + "EntitySet")
.Single(es => es.Attribute("EntityType").Value == io.QualifiedChild)
.Attribute("Name").Value;
// GET THE PARENT ENTITY SET NAME
io.ParentSet = csdlSchema.Element(csdlns + "EntityContainer")
.Elements(csdlns + "EntitySet")
.Single(es => es.Attribute("EntityType").Value == io.QualifiedParent)
.Attribute("Name").Value;
// UPDATE ALL ASSOCIATION SETS THAT REFERENCE THE CHILD ENTITY SET
foreach(var a in csdlSchema.Element(csdlns + "EntityContainer").Elements(csdlns + "AssociationSet")) {
foreach (var e in a.Elements(csdlns + "End")) {
if (e.Attribute("EntitySet").Value == io.ChildSet) e.SetAttributeValue("EntitySet", io.ParentSet);
}
}
// REMOVE THE ENTITY SET
csdlSchema.Element(csdlns + "EntityContainer")
.Elements(csdlns + "EntitySet")
.Single(es => es.Attribute("EntityType").Value == io.QualifiedChild)
.Remove();
WriteLine("<!-- ENTITY SET {0} REMOVED -->", io.QualifiedChild);
// SET BASE TYPE
EntityType.SetAttributeValue("BaseType", io.QualifiedParent);
WriteLine("<!-- BASE TYPE SET TO {0} -->", io.QualifiedParent);
// REMOVE KEY
EntityType.Element(csdlns + "Key").Remove();
WriteLine("<!-- KEY REMOVED -->");
// REMOVE ID PROPERTY
EntityType.Elements(csdlns + "Property")
.Where(etp => etp.Attribute("Name").Value == "ID")
.Remove();
WriteLine("<!-- ID PROPERTY REMOVED -->");
// REMOVE NAVIGATION PROPERTIES THAT REFERENCE THE OLD ASSOCIATION
List<XElement> NavList = new List<XElement>();
foreach (var np in csdlSchema.Descendants(csdlns + "NavigationProperty")) {
if (np.Attribute("Relationship").Value == modelns + "." + io.ForeignKey) {
WriteLine("<!-- REMOVING NAVIGATION PROPERTY {0} FROM {1} -->", np.Attribute("Name").Value, np.Parent.Attribute("Name").Value);
NavList.Add(np);
}
}
NavList.ForEach(n => n.Remove());
// REMOVE NAVIGATION PROPERTIES FROM THE PARENT THAT POINTS TO A FOREIGN KEY OF THE CHILD
foreach (var np in EntityType.Elements(csdlns + "NavigationProperty")) {
csdlSchema.Elements(csdlns + "EntityType")
.Single(cet => cet.Attribute("Name").Value == io.Parent)
.Elements(csdlns + "NavigationProperty")
.Where(pet => pet.Attribute("Name").Value == np.Attribute("Name").Value)
.Remove();
}
WriteLine("<!-- -->");
}
Write(edmx.ToString());
#>
<#+
public class InheritedObject : IEquatable<InheritedObject> {
public string ForeignKey { get; set; }
public string QualifiedParent { get; set; }
public string QualifiedChild { get; set; }
public string Parent { get { return RemoveNamespace(QualifiedParent); } }
public string Child { get { return RemoveNamespace(QualifiedChild); } }
public string ParentSet { get; set; }
public string ChildSet { get; set; }
private string RemoveNamespace(string expr) {
if (expr.LastIndexOf(".") > -1)
return expr.Substring(expr.LastIndexOf(".") + 1);
else
return expr;
}
public bool Equals(InheritedObject other) {
if (Object.ReferenceEquals(other, null)) return false;
if (Object.ReferenceEquals(this, other)) return true;
return QualifiedParent.Equals(other.QualifiedParent);
}
public override int GetHashCode() {
return QualifiedParent.GetHashCode();
}
}
#>
결과
텍스트 템플릿을 만들 것입니다 새로운 .edmx 파일 (텍스트 템플릿의 하위 파일). 이것은 완전히 자동 생성 된 외래 키 제약 조건의 이름을 기반으로 올바른 상속을 가진 모든 엔터티를 포함하는 최종 .edmx 파일입니다.
이것은 훌륭한 해결책입니다. 실제로는 edmx 파일을 변경하거나 DB로 푸시 할 수없는 실제 예제를 제공합니다. 우리는이 일을 담당하는 검사를 가지고 있습니다. –
@ kevinx007 : 잠시 전에 게시 했으므로 약간 오래된 것입니다. 이후 SQL Server 데이터베이스 연결에서 EDMX v5 파일을 만드는 데 사용하는 새 라이브러리를 만들었습니다 ... 저에게 훌륭하게 작동합니다. – BG100
다음 주셔서 감사합니다. 라이브러리 기반 솔루션과 관련하여 좀 더 자세하게 설명 할 수 있습니까? 필자는 Autogen 파일을 수정하기를 주저합니다 (EF의 새 버전이 나오고 변경 될 경우). –