Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Firebird, InterBase Новый топик    Ответить
 Ошибка с типом колонки при работе в Entity Framework в C#  [new]
microN
Member

Откуда:
Сообщений: 7
Добрый день!

Использую библиотеку FirebirdSql.Data.FirebirdClient 6.6.0. Приложение на .Net Core. В таблице задан тип колонки blob subtype 1. Провайдер видит это поле как текстовое и строку в UTF-8 размером более 8192 сохранить не может- stack overflow...
Тот же fireDAC в Delphi прекрасно обрабатывает это поле, позволяя писать в него данные как в блоб, а не в строку.
Пока что не получается заставить entity framework писать в такой блоб большие строки (либо как строки, либо как бинар.данные- не важно).
Кто сталкивался с такой задачей- что можно сделать в данной ситуации?

--
Дмитрий
11 апр 19, 12:41    [21859246]     Ответить | Цитировать Сообщить модератору
 Re: Ошибка с типом колонки при работе в Entity Framework в C#  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 47264

microN
stack overflow

Это не сообщение об ошибке Firebird. Так что отлаживайся.

Posted via ActualForum NNTP Server 1.5

11 апр 19, 12:50    [21859270]     Ответить | Цитировать Сообщить модератору
 Re: Ошибка с типом колонки при работе в Entity Framework в C#  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9388
microN,

если это ошибка .NET провайдера, а не твоего приложения пиши сюда http://tracker.firebirdsql.org/browse/DNET
11 апр 19, 13:15    [21859330]     Ответить | Цитировать Сообщить модератору
 Re: Ошибка с типом колонки при работе в Entity Framework в C#  [new]
microN
Member

Откуда:
Сообщений: 7
Может быть понятнее станет:

В модели данных описываю:

[Table("table")]
public class Test
{
[Key][Required]
public long Id {get; set; }

[Column("raw_data")]
public byte[] raw_data {get; set; }
}

В БД поле raw_data описано как: BLOB SUB_TYPE 1 SEGMENT SIZE 100 CHARACTER SET UTF8;

Т.е. это BLOB.

Делаю:
var data = db.Test.Find(id);

В Trace вижу запрос:
SELECT "e"."ID", "e"."RAW_DATA" FROM "TABLE" AS "e" WHERE "e"."ID" = CAST(@__get_Item_0 AS BIGINT)

На этом месте падает с exception:

Unable to cast object of type 'System.String' to type 'System.Byte[]'.

Видимо, проблема в драйвере. Как его заставить работать с блобом как с блобом, а не строкой?

Если я поставлю тип не byte[], а string, то оно будет работать, но размер строки ограничен 8192 байтами, что не устраивает. Отсюда и вопрос, озвученный выше, возник.

--
Дмитрий
11 апр 19, 13:48    [21859407]     Ответить | Цитировать Сообщить модератору
 Re: Ошибка с типом колонки при работе в Entity Framework в C#  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9388
microN
BLOB SUB_TYPE 1 SEGMENT SIZE 100 CHARACTER SET UTF8;


если надо работать с байтами, то обычно BLOB SUB_TYPE 0 ставят.
И да похоже сообщить в трекер придётся
11 апр 19, 13:52    [21859415]     Ответить | Цитировать Сообщить модератору
 Re: Ошибка с типом колонки при работе в Entity Framework в C#  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 47264

microN
Видимо, проблема в драйвере. Как его заставить работать с блобом как с блобом, а не строкой?

Нет, он законно отказывается конвертировать в байты строку, которую ты ему пихаешь. Не
пихай строку, пихай байты.

Posted via ActualForum NNTP Server 1.5

11 апр 19, 14:02    [21859442]     Ответить | Цитировать Сообщить модератору
 Re: Ошибка с типом колонки при работе в Entity Framework в C#  [new]
microN
Member

Откуда:
Сообщений: 7
Симонов Денис,

Денис, спасибо за наводку на трекер. Я завел там багу.

Общий вопрос:
Чтобы решить проблему сейчас, может есть какой-то workaround?

--
Дмитрий
11 апр 19, 15:10    [21859581]     Ответить | Цитировать Сообщить модератору
 Re: Ошибка с типом колонки при работе в Entity Framework в C#  [new]
Ivan_Pisarevsky
Member

Откуда: НН
Сообщений: 8239
microN
Как его заставить работать с блобом как с блобом, а не строкой?

microN
Чтобы решить проблему сейчас, может есть какой-то workaround?

cast (... as blob subtype 0)
11 апр 19, 15:18    [21859592]     Ответить | Цитировать Сообщить модератору
 Re: Ошибка с типом колонки при работе в Entity Framework в C#  [new]
Симонов Денис
Member

Откуда: Рязань
Сообщений: 9388
Ivan_Pisarevsky,

не прокатит, ибо запрос пишется самим entity framework
11 апр 19, 15:41    [21859622]     Ответить | Цитировать Сообщить модератору
 Re: Ошибка с типом колонки при работе в Entity Framework в C#  [new]
microN
Member

Откуда:
Сообщений: 7
У меня сработал такой обходной путь:

db.Test.FromSql("...cast(raw_Data as blob sub_type 0)...")

косяк при этом в том, что формируется запрос вида select from select. Мой селект entity оборачивает своим селектом. Коряво, но работает.

Примечательно то, что запись при этом происходит без ошибок- sub_type 1 тут уже нормально стыкуется с типом byte[].

--
Дмитрий
11 апр 19, 16:26    [21859684]     Ответить | Цитировать Сообщить модератору
 Re: Ошибка с типом колонки при работе в Entity Framework в C#  [new]
Коваленко Дмитрий
Member

Откуда: Липецк
Сообщений: 536
microN
Добрый день!

Использую библиотеку FirebirdSql.Data.FirebirdClient 6.6.0. Приложение на .Net Core. В таблице задан тип колонки blob subtype 1. Провайдер видит это поле как текстовое и строку в UTF-8 размером более 8192 сохранить не может- stack overflow...

Кто сталкивался с такой задачей- что можно сделать в данной ситуации?


По варварски набросанный тест с использованием другого провайдера для EF показывает, что задача вполне решабельна.

+ Пример

 private sealed class MyContext:TestBaseDbContext
 {
  [Table("TEST_MODIFY_ROW_WD")]
  public class TEST_MODIFY_ROW_WD
  {
   [Key]
   [Column("TEST_ID")]
   public Int64 TEST_ID { get; set; }

   [Column(TypeName="BLOB SUB_TYPE TEXT")]
   public string COL_TEXT_BLOB { get; set; }
  };//class TEST_MODIFY_ROW_WD

  //----------------------------------------------------------------------
  public DbSet<TEST_MODIFY_ROW_WD> testTable { get; set; }

  //----------------------------------------------------------------------
  public MyContext(xdb.OleDbTransaction tr)
   :base(tr)
  {
  }//MyContext
 };//class MyContext

 [Test]
 public static void Test_02()
 {
  var v_testStr=new string('Z',16*1024*1024); //16MB

  using(var cn=new xdb.OleDbConnection(TestServices.Conf__GetCnStr()))
  {
   cn.Open();

   using(var tr=cn.BeginTransaction())
   {
    object recID;

    using(var db=new MyContext(tr))
    {
     {
      var newRecord=new MyContext.TEST_MODIFY_ROW_WD();

      newRecord.COL_TEXT_BLOB=v_testStr;

      db.testTable.Add(newRecord);

      db.SaveChanges();

      recID=newRecord.TEST_ID;
     }//local

     int nRecs=0;

     foreach(var rec in db.testTable.Where(r=>r.TEST_ID==(Int64)recID))
     {
      Assert.AreEqual(0,nRecs);

      ++nRecs;

      Assert.AreEqual(recID,rec.TEST_ID);

      Assert.AreEqual(v_testStr,rec.COL_TEXT_BLOB);
     }//foreach rec

     Assert.AreEqual(1,nRecs);
    }//using db

    tr.Rollback();
   }//using tr
  }//using cn
 }//Test_02



+ LOG


Имя теста: Test_02
Полное имя теста: ef_core__lcpi_oledb__ntests.Work.DataTypes.Group001.Work_DataTypes_Group001__Test_011__BLOB_TEXT.Test_02
Источник теста: d:\Users\Dima\Work2\TestCode\users\Dima\TestCode\EFCore_LcpiOleDb_v1\ntest\Source\Work\DataTypes\Group001\Work_DataTypes_Group001__Test_011__BLOB_TEXT.cs : строка 95
Результаты теста: Пройден
Длительность теста: 0:00:03,517

Стандартный вывод результата:
LOG [1]: An additional 'IServiceProvider' was created for internal use by Entity Framework. An existing service provider was not used due to the following configuration changes: configuration added for 'LcpiOleDb', configuration added for 'Core:UseMemoryCache', configuration added for 'Core:EnableSensitiveDataLogging', configuration added for 'Core:EnableDetailedErrors', configuration added for 'Core:ConfigureWarnings'.
LOG [1]: Entity Framework Core 3.0.0-dev initialized 'MyContext' using provider 'EntityFrameworkCore.DataProvider.Lcpi.OleDb.nets2_0.debug' with options: None
LOG [1]: Using an existing transaction with isolation level 'ReadCommitted'.
LOG [1]: 'MyContext' generated a temporary value for the 'TEST_ID' property of new 'TEST_MODIFY_ROW_WD' entity. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values.
LOG [1]: Context 'MyContext' started tracking 'TEST_MODIFY_ROW_WD' entity. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values.
LOG [1]: SaveChanges starting for 'MyContext'.
LOG [1]: DetectChanges starting for 'MyContext'.
LOG [1]: DetectChanges completed for 'MyContext'.
LOG [1]: Executing DbCommand [Parameters=[p0='?' (Size = 2147483647), p1='?' (Size = 8) (Precision = 19) (Direction = Output) (DbType = Int64)], CommandType='Text', CommandTimeout='30']
INSERT INTO "TEST_MODIFY_ROW_WD" ("COL_TEXT_BLOB")
VALUES (:p0)
RETURNING "TEST_ID"
INTO :p1;
LOG [1]: Executed DbCommand (359ms) [Parameters=[p0='?' (Size = 2147483647), p1='?' (Size = 8) (Precision = 19) (Direction = Output) (DbType = Int64)], CommandType='Text', CommandTimeout='30']
INSERT INTO "TEST_MODIFY_ROW_WD" ("COL_TEXT_BLOB")
VALUES (:p0)
RETURNING "TEST_ID"
INTO :p1;
LOG [1]: Foreign key property 'TEST_MODIFY_ROW_WD.TEST_ID' detected as changed. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see property values.
LOG [1]: A data reader was disposed.
LOG [1]: An 'TEST_MODIFY_ROW_WD' entity tracked by 'MyContext' changed from 'Added' to 'Unchanged'. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see key values.
LOG [1]: SaveChanges completed for 'MyContext' with 1 entities written to the database.
LOG [1]: Compiling query model:
'from TEST_MODIFY_ROW_WD r in DbSet<TEST_MODIFY_ROW_WD>
where [r].TEST_ID == __recID_0
select [r]'
LOG [1]: Optimized query model:
'from TEST_MODIFY_ROW_WD r in DbSet<TEST_MODIFY_ROW_WD>
where [r].TEST_ID == __recID_0
select [r]'
LOG [1]: (QueryContext queryContext) => IEnumerable<TEST_MODIFY_ROW_WD> _InterceptExceptions(
|__ source: IEnumerable<TEST_MODIFY_ROW_WD> _TrackEntities(
| |__ results: IEnumerable<TEST_MODIFY_ROW_WD> _ShapedQuery(
| | |__ queryContext: queryContext,
| | |__ shaperCommandContext: SelectExpression:
| | | SELECT "r"."TEST_ID", "r"."COL_TEXT_BLOB"
| | | FROM "TEST_MODIFY_ROW_WD" AS "r"
| | | WHERE "r"."TEST_ID" = :__recID_0,
| | |__ shaper: (MaterializationContext materializationContext) =>
| | {
| | instance = new TEST_MODIFY_ROW_WD()
| | instance.<TEST_ID>k__BackingField = long TryReadValue(ValueBuffer materializationContext.get_ValueBuffer(), 0)
| | instance.<COL_TEXT_BLOB>k__BackingField = string TryReadValue(ValueBuffer materializationContext.get_ValueBuffer(), 1)
| | return instance
| | }),
| |__ queryContext: queryContext,
| |__ entityTrackingInfos: { itemType: TEST_MODIFY_ROW_WD },
| |__ entityAccessors: List<Func<TEST_MODIFY_ROW_WD, object>>
| {
| Func<TEST_MODIFY_ROW_WD, TEST_MODIFY_ROW_WD>,
| }),
|__ contextType: ef_core__lcpi_oledb__ntests.Work.DataTypes.Group001.Work_DataTypes_Group001__Test_011__BLOB_TEXT+MyContext,
|__ logger: DiagnosticsLogger<Query>,
|__ queryContext: queryContext)
LOG [1]: Executing DbCommand [Parameters=[__recid_0='?' (Size = 8) (Precision = 19) (DbType = Int64)], CommandType='Text', CommandTimeout='30']
SELECT "r"."TEST_ID", "r"."COL_TEXT_BLOB"
FROM "TEST_MODIFY_ROW_WD" AS "r"
WHERE "r"."TEST_ID" = :__recID_0
LOG [1]: Executed DbCommand (13ms) [Parameters=[__recid_0='?' (Size = 8) (Precision = 19) (DbType = Int64)], CommandType='Text', CommandTimeout='30']
SELECT "r"."TEST_ID", "r"."COL_TEXT_BLOB"
FROM "TEST_MODIFY_ROW_WD" AS "r"
WHERE "r"."TEST_ID" = :__recID_0
LOG [1]: A data reader was disposed.
LOG [1]: 'MyContext' disposed.



Так что дергай своего "производителя" адаптера для EF - пусть разбирается :)
11 апр 19, 16:33    [21859697]     Ответить | Цитировать Сообщить модератору
Все форумы / Firebird, InterBase Ответить