簡體   English   中英

如何使用 ValueConversions 檢索 Entity Framework Core 的數據庫模型

[英]How to retrieve a database model for Entity Framework Core with ValueConversions

我有一個 asp.net 核心 web api 項目,我使用實體框架。 我從 Web 獲取 DTO 並轉換(使用 AutoMapper)到數據庫實體。

在這一點上,我可以在服務器上對實體進行一些后期處理,然后再訪問數據庫。 由於實體框架中的數據庫結構和限制,我需要將此實體傳遞給存儲過程。 在這一點上,我想應用 WITH 轉換的數據庫模型。

基本上,這個流...

控制器接受 DTO -> AutoMapper 到實體 -> 允許我在保存之前處理對象並做一些事情 -> 保存,但使用存儲過程。

我的模型有一個轉換,那么我如何在執行查詢時獲得我想要的數據庫表示?

問題是我在控制器中得到“false”作為參數,這在實體模型中被轉換為布爾值,當我想保存它時它被轉換為字符串(“false”),我如何應用轉換在實體框架模型中定義,以便我可以按預期保存“Y”或“N”?

下面的簡化示例...

為了澄清這個問題,我需要能夠在調用存儲過程之前獲得模型的數據庫表示,使用下面的代碼,將調用 ToString,所以我將得到“false”而不是“N”。 在檢索數據時,我有一種方法可以使用 ValueConversions(即數據庫 - > 模型)來執行此操作。 如果我使用 SaveChanges,EF Core 會處理轉換(模型 -> 數據庫),但是當使用原始 SQL(在存儲過程的情況下)時,我如何獲取數據庫表示。 在這一點上,如果我的模型有一個布爾屬性,我想將“Y”或“N”作為參數傳遞給原始 SQL……這樣更清楚嗎?

public class TodoDto
{
    [ReadOnly(true)]
    public long Id{ get; set; }

    public string Item { get; set; }

    public bool Done { get; set; }

    public DateTime? DateStamp { get; set; }
    // other properties, model is more complex, but removed to keep it simple
}

public class TodoEFCoreModel
{
    [Column("TodoId"), ReadOnly(true)]
    public long Id { get; set; }

    [Column("TodoItem")]
    public string Item { get; set; }

    public bool? Done { get; set; }

    public DateTime? DateStamp { get; set; }
    // other properties
}    

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    var yesNoConversion = new YesNoToBoolConverter();

    modelBuilder
        .Entity<TodoEFCoreModel>()
        .Property(x => x.Done)
        .HasConversion(yesNoConversion);
}

public ActionResult PostToDo(TodoDto todo)
{
    // code is then roughly
    var databaseTodoEntity = _mapper.Map<TodoDto, TodoEFCoreModel>(todo);

    // here I can check databaseTodoEntity boolean property
    // and/or manipulate the model

    // when it comes to saving I need to use a stored procedure, I can do this using ExecuteSqlCommandAsync...
    await _dbContext.Database.ExecuteSqlCommandAsync("begin CreateTodo(Item => :p0, Done => :p1, DateStamp => :p2); end;", parameters: new[]
        {
            new OracleParameter("p0", OracleDbType.VarChar2, databaseTodoEntity.Item, ParameterDirection.Input),

            // The problem is here, with this code I get "false", instead of the conversion that Entity Framework would apply if I were to be able to call "SaveChanges" on the db context...
            new OracleParameter("p1", OracleDbType.Varchar2, databaseTodoEntity.Done, ParameterDirection.Input),

            new OracleParameter("p2", OracleDbType.Date, databaseTodoEntity.DateStamp, ParameterDirection.Input)
        });
}

EF Core 在內部使用RelationalTypeMapping類實例

表示 .NET 類型和數據庫類型之間的映射。

對於特定的實體屬性,可以使用FindRelationalMapping擴展方法獲取。

請注意,此方法被視為“內部”API 的一部分,因此您需要

using Microsoft.EntityFrameworkCore.Internal;

並接受典型的警告

此 API 支持 Entity Framework Core 基礎結構,不應直接從您的代碼中使用。 此 API 可能會在未來版本中更改或刪除。

現在,除了Converter和其他有用的屬性外,您還可以訪問一些有用的方法,如CreateParameter ,它們可以直接在您的場景中使用。 它將像使用 EF Core 生成的命令一樣進行所有必要的轉換和參數准備。

例如:

var sql = "begin CreateTodo(Item => :p0, Done => :p1, DateStamp => :p2); end;";
var entityType = _dbContext.Model.FindEntityType(typeof(TodoEFCoreModel));
var dbCommand = _dbContext.Database.GetDbConnection().CreateCommand();
object[] parameters =
{
    entityType.FindProperty("Item").FindRelationalMapping()
        .CreateParameter(dbCommand, "p0", databaseTodoEntity.Item),
    entityType.FindProperty("Done").FindRelationalMapping()
        .CreateParameter(dbCommand, "p1", databaseTodoEntity.Done),
    entityType.FindProperty("DateStamp").FindRelationalMapping()
        .CreateParameter(dbCommand, "p2", databaseTodoEntity.DateStamp),
};
await _dbContext.Database.ExecuteSqlCommandAsync(sql, parameters);

請注意, DbCommand實例僅用作DbParameter工廠 ( DbCommand.CreateParameter )。 創建的參數不會添加到該命令中,因此之后可以安全地將其丟棄。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM