通过EF Core获取SQL列def返回错误的结果吗?

时间:2019-06-10 20:05:52

标签: c# sql-server entity-framework-core

我对SaveChanges()进行了覆盖,以希望当有数据将被截断时希望捕获。处理定义不明确的数据结构,因此必须对适合的数据做出很多猜测。我只是更改了覆盖以发送出包含“ [n] VAR [char]”类型的所有列,这就是它捕获的内容:

JobUpcomingRenewal.JobResult NVARCHAR(MAX) :: JobResult(9) = Succeeded
JobUpcomingRenewal.Message NVARCHAR(MAX) :: Message(54) = Updated UpcomingRenewal, ready for marketo job pickup.
JobUpcomingRenewal.SubscriptionNumber NVARCHAR(MAX) :: SubscriptionNumber(32) = 2c92a00a6a07e3ce016a0833708a4274
ImportUpcomingRenewal.AccountNumber NVARCHAR(MAX) :: AccountNumber(9) = A00012018 
ImportUpcomingRenewal.Email NVARCHAR(MAX) :: Email(21) = $$$$$$$$$@hotmail.com 
ImportUpcomingRenewal.FirstName NVARCHAR(MAX) :: FirstName(3) = $$$ 
ImportUpcomingRenewal.JobResult NVARCHAR(MAX) :: JobResult(-1) =  
ImportUpcomingRenewal.LastName NVARCHAR(MAX) :: LastName(3) = $$$ 
ImportUpcomingRenewal.Message NVARCHAR(MAX) :: Message(-1) =  
ImportUpcomingRenewal.PaymentMethod NVARCHAR(MAX) :: PaymentMethod(10) = CreditCard 
ImportUpcomingRenewal.Product NVARCHAR(MAX) :: Product(6) = Uknown
ImportUpcomingRenewal.RatePlanChargeName NVARCHAR(MAX) :: RatePlanChargeName(6) = Uknown
ImportUpcomingRenewal.RatePlanName NVARCHAR(MAX) :: RatePlanName(6) = Uknown
ImportUpcomingRenewal.SubscriptionNumber NVARCHAR(MAX) :: SubscriptionNumber(11) = A-S00073392
ZuoraMiddlewareAction.Name NVARCHAR(MAX) :: Name(15) = UpcomingRenewal
ZuoraMiddlewareAction.RecordNumber NVARCHAR(MAX) :: RecordNumber(32) = 2c92a00a6a07e3ce016a0833708a4274 
ZuoraMiddlewareAction.Type NVARCHAR(MAX) :: Type(12) = Subscription 
An error occurred while updating the entries. See the inner exception for details. 
String or binary data would be truncated.

表定义示例为:

/****** Object:  Table [Zuora].[JobUpcomingRenewal]    Script Date: 6/10/2019 3:44:55 PM ******/
CREATE TABLE [Zuora].[JobUpcomingRenewal](
[SubscriptionNumber] [varchar](255) NULL,
[SubscriptionTermEndDate] [date] NULL,
[TriggeredOn] [datetime2] NOT NULL,
[JobStamp] [datetime2] NULL,
[JobResult] [varchar](255) NULL,
[Id] [uniqueidentifier] NOT NULL,
[Message] [varchar](4000) NULL
) ON [PRIMARY]

1)我不对这些表使用NVARCHAR, 2)我只能想到的一列定义为VARCHAR(MAX)-其他所有内容都是VARCHAR(NN)

我覆盖的代码:

public override int SaveChanges()
{
    using (LogContext.PushProperty("DbContext:Override:Save", nameof(SaveChanges)))
    {
        try
        {
            return base.SaveChanges();
        }
        catch (Exception ex)
        {
            Log.Warning(ex, "Attempting to handle error {Message}", ex.FullMessage());
            var errorMessage = "";
            var token = Environment.NewLine;

            foreach (var entityEntry in this.ChangeTracker.Entries().Where(et => et.State != EntityState.Unchanged))
            {
                foreach (var entry in entityEntry.CurrentValues.Properties)
                {
                    var result = entityEntry.GetDatabaseDefinition(entry.Name);
                    var value = entry.PropertyInfo.GetValue(entityEntry.Entity);
                    if (result.IsFixedLength && value.ToLength() > result.MaxLength)
                    {
                        errorMessage = $"{errorMessage}{token}ERROR!! <<< {result.TableName}.{result.ColumnName} {result.ColumnType.ToUpper()} :: {entry.Name}({value.ToLength()}) = {value} >>>";
                        Log.Warning("Cannot save data to SQL column {TableName}.{ColumnName}!  Max length is {LengthTarget} and you are trying to save something that is {LengthSource}.  Column definition is {ColumnType}"
                            , result.TableName
                            , result.ColumnName
                            , result.MaxLength
                            , value.ToLength()
                            , result.ColumnType);
                    }
                    if(result.ColumnType.Contains("var", StringComparison.CurrentCultureIgnoreCase)) // varchar, nvarchar, varbinary, etc...
                    {
                        errorMessage = $"{errorMessage}{token}WARNING!! <<< {result.TableName}.{result.ColumnName} {result.ColumnType.ToUpper()} :: {entry.Name}({value.ToLength()}) = {value} >>>";
                        Log.Warning("Cannot save data to SQL column {TableName}.{ColumnName}!  Max length is {LengthTarget} and you are trying to save something that is {LengthSource}.  Column definition is {ColumnType}"
                            , result.TableName
                            , result.ColumnName
                            , result.MaxLength
                            , value.ToLength()
                            , result.ColumnType);
                    }
                    //else
                    //    errorMessage = $"{errorMessage}{token}{result.TableName}.{result.ColumnName} {result.ColumnType.ToUpper()} :: {entry.Name}({value.ToLength()}) = {value}";
                }
            }
            throw new Exception(errorMessage, ex);
        }
    }
}

支持代码:

public class DataInfoModel
{
    public string TableName { get; set; }
    public string ColumnName { get; private set; } = "Unknown";
    public string ColumnType { get; private set; } = "Unknown";
    public int MaxLength { get; set; } = 0;
    public bool IsFixedLength { get; private set; } = false;


    public void SetSqlInfo(Microsoft.EntityFrameworkCore.Metadata.IEntityType table, Microsoft.EntityFrameworkCore.Metadata.IProperty property)
    {
        TableName = table.Name.Substring(table.Name.LastIndexOf(".") + 1);

        var sqlInfo = property.SqlServer();
        ColumnName = sqlInfo.ColumnName;
        ColumnType = sqlInfo.ColumnType;
        IsFixedLength = sqlInfo.IsFixedLength;  // always returns false!  Why?

        if (property.GetMaxLength().HasValue)
        {
            MaxLength = property.GetMaxLength().Value;
            if (MaxLength > 0)
                IsFixedLength = true;
        }
    }
}

public static class ExtendDataInfoModel
{
    public static DataInfoModel GetDatabaseDefinition(this EntityEntry entityEntry, string columnName)
    {
        var result = new DataInfoModel();

        var table = entityEntry.Metadata.Model.FindEntityType(entityEntry.Metadata.ClrType);

        var property = table.GetProperties().ToList().FirstOrDefault(a => a.Name.Equals(columnName, StringComparison.CurrentCultureIgnoreCase));
        if (property == null)
            return result;

        result.SetSqlInfo(table, property);
        return result;
    }
    public static int ToLength(this object source)
    {
        if (source == null)
            return -1;
        return source.ToString().Length;
    }
}

让我着迷的另一件事是,上周它似乎可以正常工作,并且正在捕获错误(列数据将被截断)就很好了。这周不是。我确实在数据库添加/更新周围添加了db.Database.StartTransaction()包装器。这会影响上面的代码吗?

0 个答案:

没有答案