问题
I have been using Entity Framework model first since VS 2010. When I build my project, EF generates a Model.Designer.cs file containing all entities. This designer file also contains the documentation added to the entities in the EDMX file.
When I created a new EF model first project in VS 2012, a Model.tt file is added to my EDMX file. This T4 template generates a single file for every entity in my model. Unfortunately, the documentation from the EDMX file is not used in the generated code.
I really like having my model documented so IntelliSense shows up when using it. The only workaround I have found so far is remove the Model.tt and the generated class files and turning the code generation on my EDMX file back on. This reverts back to the behaviour I am used from VS 2010. However, I would prefer having a separate file per entity.
Is there any way (preferably using VS tools and without having to modify any files that ship with VS) to include the documentation from the EDMX file in the generated single class files?
Edit: To further illustrate my problem, here is a quick example.
Let's say my model looks like this:
I have highlighted the part where I entered the documentation in the Properties window of the Id property.
This is what the entity looks like in the EDMX file:
<EntityType Name="Entity1">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Type="Int32" Name="Id" Nullable="false" annotation:StoreGeneratedPattern="Identity" >
<Documentation>
<Summary>This is documentation for the ID property.</Summary>
</Documentation>
</Property>
</EntityType>
The generated class (Entity1.cs) by Model.tt looks like this:
public partial class Entity1
{
public int Id { get; set; }
}
But when I turn on the code generation for my model, this is what the entity looks like in Model.Designer.cs:
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmEntityTypeAttribute(NamespaceName="Model1", Name="Entity1")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class Entity1 : EntityObject
{
#region Factory Method
/// <summary>
/// Create a new Entity1 object.
/// </summary>
/// <param name="id">Initial value of the Id property.</param>
public static Entity1 CreateEntity1(global::System.Int32 id)
{
Entity1 entity1 = new Entity1();
entity1.Id = id;
return entity1;
}
#endregion
#region Simple Properties
/// <summary>
/// This is documentation for the ID property.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int32 Id
{
get
{
return _Id;
}
set
{
if (_Id != value)
{
OnIdChanging(value);
ReportPropertyChanging("Id");
_Id = StructuralObject.SetValidValue(value, "Id");
ReportPropertyChanged("Id");
OnIdChanged();
}
}
}
private global::System.Int32 _Id;
partial void OnIdChanging(global::System.Int32 value);
partial void OnIdChanged();
#endregion
}
So you see: Model.Designer.cs contains my custom documentation string "This is documentation for the ID property." while Entity1.cs does not. However, Model.Designer.cs can get quite big if there are many entities and debugging into this file is somewhat slow. I'd prefer having several small files (one per entity), but still preserve the documentation from the EDMX file in the generated code.
回答1:
I think you'll have to modified the T4 file. I've got the same problem and read through the T4 file a bit, and tried to follow the instruction here: http://karlz.net/blog/index.php/2010/01/16/xml-comments-for-entity-framework/
However, we're using VS 2012 and the instruction doesn't seem to work 100%. I ended up changing the property generation code at the end of the T4 file and it works exactly how I wanted it to be. The changes are in CodeStringGenerator.Property() and CodeStringGenerator.NavigationProperty()
public string Property(EdmProperty edmProperty)
{
string doc = "";
if (edmProperty.Documentation != null)
{
doc = string.Format(
CultureInfo.InvariantCulture,
"\n\t\t/// <summary>\n\t\t/// {0} - {1}\n\t\t/// </summary>\n\t\t",
edmProperty.Documentation.Summary ?? "",
edmProperty.Documentation.LongDescription ?? "");
}
return doc + string.Format(
CultureInfo.InvariantCulture,
"{0} {1} {2} {{ {3}get; {4}set; }}",
Accessibility.ForProperty(edmProperty),
_typeMapper.GetTypeName(edmProperty.TypeUsage),
_code.Escape(edmProperty),
_code.SpaceAfter(Accessibility.ForGetter(edmProperty)),
_code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
}
public string NavigationProperty(NavigationProperty navigationProperty)
{
var endType = _typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType());
string doc = "";
if (navigationProperty.Documentation != null)
{
doc = string.Format(
CultureInfo.InvariantCulture,
"\n\t\t/// <summary>\n\t\t/// {0} - {1}\n\t\t/// </summary>\n\t\t",
navigationProperty.Documentation.Summary ?? "",
navigationProperty.Documentation.LongDescription ?? "");
}
return doc + string.Format(
CultureInfo.InvariantCulture,
"{0} {1} {2} {{ {3}get; {4}set; }}",
AccessibilityAndVirtual(Accessibility.ForProperty(navigationProperty)),
navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType,
_code.Escape(navigationProperty),
_code.SpaceAfter(Accessibility.ForGetter(navigationProperty)),
_code.SpaceAfter(Accessibility.ForSetter(navigationProperty)));
}
Note that it won't work with class documentation, so you have to do something like this with entity and complex type
<#=codeStringGenerator.UsingDirectives(inHeader: false)#>
<#if (!ReferenceEquals(entity.Documentation, null))
{
#>
/// <summary>
/// <#=entity.Documentation.Summary#> – <#=entity.Documentation.LongDescription#>
/// </summary>
<#}#>
<#=codeStringGenerator.EntityClassOpening(entity)#>
来源:https://stackoverflow.com/questions/13931159/add-documentation-to-generated-code-in-entity-framework-model-first