【问题标题】:Map foreign key to scalar property将外键映射到标量属性
【发布时间】:2016-12-06 09:29:58
【问题描述】:

我有 2 张桌子:DataAdditionalData。它们的关系是 1 到 1-0(任何 Data 都可以有 0 或 1 个 AdditionalData)。

对于主要上下文我有类:

class Data
{
    public long Id {get;set;} // PK
    public string Name {get;set;}
    public AdditionalData AdditionalData {get;set;} // can be null
}

class AdditionalData
{
    public long Id {get;set;} // PK
    public string AdditionalName {get;set;}
}

这很好用。

对于另一种情况,我只需要知道Data 是否有AdditionalData

class ExtendedData
{
    public long Id {get;set;} //PK
    public string Name {get;set;}
    public bool HasAdditionalData {get;set;}
}

我可以将其映射到视图:

SELECT 
     d.*
    ,IIF(ad.Id IS NULL, 0, 1) AS HasAdditionalData
FROM Data AS d
LEFT OUTER JOIN AdditionalData AS ad ON d.Id = ad.Id

但我想知道:

我可以将ExtendedData 类映射到没有额外视图的表吗?

【问题讨论】:

  • @GertArnold 不,在第二种情况下,我注意到AdditionalData 进行编辑

标签: c# .net sql-server entity-framework


【解决方案1】:

如果您可以将ExtendedData 用作投影结果,那么您可能正在寻找如下查询:

var result = ctx.Data.Select(d => new ExtendedData {Id = d.Id, Name = d.Name, HasAdditionalData = d.ApprovalStatus != null);

问题是你的PK也扮演着FK的双重职责,如果你将AdditionalData的FK定义为另一个字段,可能AdditionalDataId可以为空,那么检查AdditionalData的存在将是微不足道的;只需检查AdditionalDataId 是否为空,您也会获得更好的性能。

【讨论】:

  • 想象AdditionalData 对象很重(大约1mb),所以从数据库中加载它很奇怪,只是为了检查它是否为空
  • @Backs 检查 FK(AdditionalDataId 属性)不会加载对象。仅访问 FK id 属性不会触发延迟加载。
  • 哦,我明白了,你的意思。是的,这可以工作,如果我有额外的列 AdditionalDataId 具有唯一值。这是一个有点复杂的架构。但有可能,是的
  • 这是一个 1 到 min 0:max 1 的关系,对吧?所以它应该可以正常工作。确保AdditionalDataIdData 表上是可选的(可为空)。
  • 无论如何,它看起来像是某种解决方法。我必须在模型中添加一些不必要的属性
【解决方案2】:

您可以避免使用DefiningQuery 构造创建数据库视图。 DefiningQuery 提供与数据库视图相同的功能,但它是在您的模型中定义的,而不是在数据库本身中。

您不能使用 Visual Studio 模型设计器创建 DefiningQuery,您应该手动编辑您的 edmx 文件。首先将EntityTypeEntitySet定义添加到SSDL层:

<!-- SSDL content -->
<edmx:StorageModels>
<Schema Namespace="TestDataModel.Store" Provider="System.Data.SqlClient" ProviderManifestToken="2012" Alias="Self" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns:customannotation="http://schemas.microsoft.com/ado/2013/11/edm/customannotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm/ssdl">

  <EntityType Name="ExtendedData">
    <Key>
      <PropertyRef Name="Id" />
    </Key>
    <Property Name="Id" Type="bigint" Nullable="false" StoreGeneratedPattern="Identity" />
    <Property Name="Name" Type="nvarchar(max)" Nullable="false" />
    <Property Name="HasAdditionalData" Type="bit" Nullable="false" />
  </EntityType>

  <EntityContainer Name="TestDataModelStoreContainer">
    <EntitySet Name="ExtendedData" EntityType="Self.ExtendedData" store:Type="Views" store:Schema="dbo" store:Name="ExtendedData">
      <DefiningQuery>
        SELECT d.Id, d.Name, CAST(IIF(ad.Id IS NULL, 0, 1) AS BIT) AS HasAdditionalData
        FROM Data AS d
        LEFT OUTER JOIN AdditionalData AS ad ON d.Id = ad.Id
      </DefiningQuery>
    </EntitySet>
  </EntityContainer>

</Schema></edmx:StorageModels>

请注意,您的 View 查询是在 DefiningQuery 元素下指定的,但略有更改。

然后您应该将ExtendedData 实体添加到 CSDL。这可以通过进一步手动编辑 edmx 或使用模型设计器来完成。这是它最终的样子:

<!-- CSDL content -->
<edmx:ConceptualModels>
  <Schema Namespace="TestDataModel" Alias="Self" annotation:UseStrongSpatialTypes="false" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns:customannotation="http://schemas.microsoft.com/ado/2013/11/edm/customannotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
    <EntityContainer Name="TestDataEntities2" annotation:LazyLoadingEnabled="true">
      <EntitySet Name="ExtendedDatas" EntityType="TestDataModel.ExtendedData" />
    </EntityContainer>
    <EntityType Name="ExtendedData">
      <Key>
        <PropertyRef Name="Id" />
      </Key>
      <Property Name="Id" Type="Int64" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
      <Property Name="Name" Type="String" Nullable="false" />
      <Property Name="HasAdditionalData" Type="Boolean" Nullable="false" />
    </EntityType>
  </Schema>
</edmx:ConceptualModels>

然后你应该添加 CSDL-SSDL 映射,再次手动编辑 edmx 或通过 Table Mapping:

<!-- C-S mapping content -->
<edmx:Mappings>
  <Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2009/11/mapping/cs">
    <EntityContainerMapping StorageEntityContainer="TestDataModelStoreContainer" CdmEntityContainer="TestDataEntities2">
      <EntitySetMapping Name="ExtendedDatas">
        <EntityTypeMapping TypeName="IsTypeOf(TestDataModel.ExtendedData)">
          <MappingFragment StoreEntitySet="ExtendedData">
            <ScalarProperty Name="HasAdditionalData" ColumnName="HasAdditionalData" />
            <ScalarProperty Name="Name" ColumnName="Name" />
            <ScalarProperty Name="Id" ColumnName="Id" />
          </MappingFragment>
        </EntityTypeMapping>
      </EntitySetMapping>
    </EntityContainerMapping>
  </Mapping>
</edmx:Mappings>

请注意:如果您从数据库更新模型,则 edmx 的 SSDL 部分中的任何手动更改都将丢失。

【讨论】:

  • 有趣的解决方案,当你有 edmx-file 时
猜你喜欢
  • 2018-11-19
  • 1970-01-01
  • 2013-12-12
  • 1970-01-01
  • 1970-01-01
  • 2011-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多