6

我正在使用反射和类型生成器构建一个动态类,我想知道如何直接将类型转换为 c# 类型

目前我正在这样做,但是EF提供了这种东西吗?

 case "uniqueidentifier":
                return typeof(Guid);
            case "bit":
                return typeof(Boolean);
            case "nvarchar":
                return (typeof(string));
            case "datetime":
                return typeof(DateTime);
            case "float":
                return typeof(double);
            case "int":
                return (typeof(int));

谢谢

更新 我假设到目前为止 EF 还没有提供可公开访问的实用程序。接受的答案与 Ef 无关。那里的图书馆很不一样。

Ryszard Dżegan 给出了答案,但它不能在 TT 模板或 edmx 之外使用(或者我可能不知道)

4

2 回答 2

4

我不知道这样的公共方法(我认为没有......它可以被接受为答案)

但是,尝试反编译 sqlmetal.exe,您可以很好地了解默认关联是如何在内部实现的:

在 LinqToSqlShared.Utility.DbTypeSystem 类(内部类)中,您可以找到该方法:

internal static Type GetClosestRuntimeType(SqlDbType sqlDbType)
{
switch (sqlDbType)
{
    case SqlDbType.BigInt:
        return typeof(long);

    case SqlDbType.Binary:
    case SqlDbType.Image:
    case SqlDbType.Timestamp:
    case SqlDbType.VarBinary:
        return typeof(Binary);

    case SqlDbType.Bit:
        return typeof(bool);

    case SqlDbType.Char:
    case SqlDbType.NChar:
    case SqlDbType.NText:
    case SqlDbType.NVarChar:
    case SqlDbType.Text:
    case SqlDbType.VarChar:
        return typeof(string);

    case SqlDbType.DateTime:
    case SqlDbType.SmallDateTime:
    case SqlDbType.Date:
    case SqlDbType.DateTime2:
        return typeof(DateTime);

    case SqlDbType.Decimal:
    case SqlDbType.Money:
    case SqlDbType.SmallMoney:
        return typeof(decimal);

    case SqlDbType.Float:
        return typeof(double);

    case SqlDbType.Int:
        return typeof(int);

    case SqlDbType.Real:
        return typeof(float);

    case SqlDbType.UniqueIdentifier:
        return typeof(Guid);

    case SqlDbType.SmallInt:
        return typeof(short);

    case SqlDbType.TinyInt:
        return typeof(byte);

    case SqlDbType.Xml:
        return typeof(XElement);

    case SqlDbType.Time:
        return typeof(TimeSpan);

    case SqlDbType.DateTimeOffset:
        return typeof(DateTimeOffset);
}
return typeof(object);
}

编辑

  • 将此作为参考

  • 同一个类中还有一个方法static SqlDbType Parse(string stype),它从 sql 类型字符串定义中返回一个枚举 SqlDbType。

于 2013-11-04T10:54:31.727 回答
2

我可以假设,由于实体框架能够在概念模型和存储模型之间创建映射,它具有将每个数据库类型转换为相应概念类型的内部能力。

此外,Entity Framework 使用其 T4 模板中的 EF.Utility.CS.ttinclude 标头中存在的辅助类来生成上下文和实体源文件。

EF.Utility.CS.ttinclude 反过来在内部使用System.Data.Metadata.Edm 命名空间中的类,特别是PrimitiveTypeKind 枚举,它涵盖概念类型并构成数据库类型和 CLR 类型之间的桥梁。

PrimitiveTypeKind Enumeration的值可以作为PrimitiveType Class中的属性找到,并且该类还有另一个有趣的属性,称为ClrEquivalentType,它按预期返回System.Type

PrimitiveType 类实例可以通过多种方式获取。在 T4 模板中,实体框架与具有GetPrimitiveTypes Method的EdmItemCollection 类一起使用。

在 T4 模板中,访问EdmItemCollection 类的最简单方法是使用 MetadataLoader(来自 EF.Utility.CS.ttinclude)的 CreateEdmItemCollection 方法,该方法将 edmx 文件的参数路径作为参数。

在 tt 文件中,您可以编写:

<#@ template hostSpecific="true" #>
<#@ output extension=".txt" #>
<#@ include file="EF.Utility.CS.ttinclude" #><#

var edmxPath = "NorthwindModel.edmx"; // <--- Put the path to your model here.
var loader = new MetadataLoader(this);
var edmItemCollection = loader.CreateEdmItemCollection(edmxPath);
var primitiveTypes = edmItemCollection.GetPrimitiveTypes();

#>
<#
foreach (var primitiveType in primitiveTypes)
{
#>
<#= primitiveType#> ==> <#= primitiveType.ClrEquivalentType#>
<#
}
#>

结果将是:

Edm.Binary ==> System.Byte[]
Edm.Boolean ==> System.Boolean
Edm.Byte ==> System.Byte
Edm.DateTime ==> System.DateTime
Edm.Decimal ==> System.Decimal
Edm.Double ==> System.Double
Edm.Guid ==> System.Guid
Edm.Single ==> System.Single
Edm.SByte ==> System.SByte
Edm.Int16 ==> System.Int16
Edm.Int32 ==> System.Int32
Edm.Int64 ==> System.Int64
Edm.String ==> System.String
Edm.Time ==> System.TimeSpan
Edm.DateTimeOffset ==> System.DateTimeOffset
Edm.Geometry ==> System.Data.Spatial.DbGeometry
Edm.Geography ==> System.Data.Spatial.DbGeography
Edm.GeometryPoint ==> System.Data.Spatial.DbGeometry
Edm.GeometryLineString ==> System.Data.Spatial.DbGeometry
Edm.GeometryPolygon ==> System.Data.Spatial.DbGeometry
Edm.GeometryMultiPoint ==> System.Data.Spatial.DbGeometry
Edm.GeometryMultiLineString ==> System.Data.Spatial.DbGeometry
Edm.GeometryMultiPolygon ==> System.Data.Spatial.DbGeometry
Edm.GeometryCollection ==> System.Data.Spatial.DbGeometry
Edm.GeographyPoint ==> System.Data.Spatial.DbGeography
Edm.GeographyLineString ==> System.Data.Spatial.DbGeography
Edm.GeographyPolygon ==> System.Data.Spatial.DbGeography
Edm.GeographyMultiPoint ==> System.Data.Spatial.DbGeography
Edm.GeographyMultiLineString ==> System.Data.Spatial.DbGeography
Edm.GeographyMultiPolygon ==> System.Data.Spatial.DbGeography
Edm.GeographyCollection ==> System.Data.Spatial.DbGeography

在普通的 C# 代码中,如果你有 MetadataLoader,你可以做同样的事情。要省略这个障碍,您只需将 MetadataLoader 类复制到您的代码中即可。但是,还有其他方法可以实现该目标。如果您使用 Code First 方法,有趣的解决方案是使用EdmxWriter.WriteEdmx 方法(DbContext,XmlWriter)以便在MemoryStream中动态创建 edmx 文件,然后将该流作为参数放入XmlReader.Create 方法(Stream),最后使用xml 阅读器作为EdmItemCollection 构造函数 (IEnumerable)中的输入参数。

还有一些方法可以用 C# 类型 (Nullable<System.Int32> ==> int?) 替换 CLR 类型,但这是另一回事......

于 2013-11-06T10:08:10.133 回答