Lambda无法进行Int16比较吗?

时间:2019-08-19 20:44:56

标签: c# .net visual-studio

我的c#(.NET 4.7.1)代码中包含以下lambda expression

DataRow[] skmRows = dtSKM.AsEnumerable().Where(x =>
   x.Field<int>("NDRAWING1").Equals(NDRAWING1) &&
   x.Field<Int16>("NDRAWING2").Equals(NDRAWING2)
   ).ToArray();

所有内容都会编译,并且在运行时不会引发任何异常。问题在于上面的lambda表达式应该获得结果-但事实并非如此。我在断点处停下来,并验证了应该发生匹配的DataRows

因此,我然后将此表达式复制到Immediate的{​​{1}}窗口中并运行它-并且它 DID 获得匹配的DataRows。 WTH ??

所以我想知道VS2017。 MSSQL中的相关列是Int16,它映射到C#中的INT16。对于踢,我将sql server中的数据类型从smallint更改为int,从而更改了我的lambda:

SMALLINT

...而且有效!! (我得到了预期的匹配行。)

这使我得出结论,.NET中存在一个错误,在该错误中,运行时无法根据smallint sql服务器列值正确评估Int16比较。

除了 bug 之外,还有其他解释吗?我猜这对任何人来说都应该很容易复制。整理一个lambda,使其与MSSQL中的SMALLINT列匹配,看看会发生什么。

1 个答案:

答案 0 :(得分:3)

smallint 确实映射到 int16 ,也称为 short 。您可以在adonet server data type mappings进行验证。至于发生了什么,请检查int16等于= "true if obj is an instance of Int16 and equals the value of this instance; otherwise, false."的文档。

变量 NDRAWING2 也必须为 int16 。在Javascript中,运算符“ ===”表示值必须相同且类型相同。


通过适当的抽象,使用Microsoft.EntityFrameworkCore.InMemory 2.2.6和NUnit 3.2,我将:

  • 在内存数据库上下文中创建
  • 将上下文添加到服务
  • 使用服务添加一些数据并将其存储到db
  • 验证它是否在新的上下文中有数据
  • 使用服务查找我想要的数据
  • 验证它确实找到了数据

代码示例:

class Program
{
    static void Main(string[] args)
    {
        var options = new DbContextOptionsBuilder<DtSkmContext>()
            .UseInMemoryDatabase(databaseName: "Add_writes_to_database")
            .Options;

        using (var context = new DtSkmContext(options))
        {
            var service = new DtSkmService(context);
            service.Add(3, 7);
            context.SaveChanges();
        }

        using (var context = new DtSkmContext(options))
        {
            Assert.That(context.DtSkm.Count(), Is.EqualTo(1));

            var service = new DtSkmService(context);
            var result = service.Find(3, 7);

            Assert.That(result, Is.Not.Null);
        }
    }
}

服务

public class DtSkmService
{
    private DtSkmContext _context;

    public DtSkmService(DtSkmContext context)
    {
        _context = context;
    }

    public void Add(int ndrawing1, Int16 ndrawing2)
    {
        var dtSkm = new DtSkmDto { Ndrawing1 = ndrawing1, Ndrawing2 = ndrawing2 };
        _context.DtSkm.Add(dtSkm);
        _context.SaveChanges();
    }

    public IEnumerable<DtSkmDto> Find(int first, Int16 second)
    {
        return _context.DtSkm
            .Where(b => b.Ndrawing1.Equals(first) && b.Ndrawing2.Equals(second))
            .OrderBy(b => b.Ndrawing1)
            .ToList();
    }
}

以及dto和上下文

public class DtSkmDto
{
    public int Id { get; set; }
    [Required]
    public int Ndrawing1 { get; set; }
    [Required]
    public Int16 Ndrawing2 { get; set; }
}
public class DtSkmContext : DbContext
{
    public DtSkmContext()
    {
    }
    public DtSkmContext(DbContextOptions<DtSkmContext> options) : base(options)
    {
    }
    public DbSet<DtSkmDto> DtSkm { get; set; }
}

虽然此方法使用EF内核并在内存db中,但它显示了一种实现方法。在您的情况下,您可以进行以下更改:

var data = dtSKM.AsEnumerable().ToList();
DataRow[] skmRows = data.Where(x =>
   x.Field<int>("NDRAWING1").Equals(NDRAWING1) &&
   x.Field<Int16>("NDRAWING2").Equals(NDRAWING2)
   ).ToArray();

,您可以使用调试器验证数据实例的类型/值。您的假设之​​一不成立,也不是“ .NET中的错误”。