用EF Core,Dapper和SQLClient插入/读取SQL-Server图像
#教程 #database #csharp #dotnetcore

使用EF Core/dapper/sqlclient基础知识

学习如何使用DapperEntity Framework CoreSqlClient数据提供商读取和插入图像中的图像。

对于新手甚至中级开发人员,使用图像的开发人员可能是一项艰巨的任务,因为他们要么编写代码,期望它立即工作,而无需对使用适当的数据类型或从Internet复制粘贴代码而不更改太多的内容。并期望代码工作。

要吸引主要受众,使用了三种不同的方法,dapper,ef core和sqlclient数据提供商。

使用正确的数据类型

没有使用图像经验的开发人员会选择图像经文Varbinary(Max)未意识到图像类型的开发人员最有可能在SQL-Server的将来版本中删除。这意味着,不要使用图像,而是使用varbinary(max)。

代码样本的列定义

table definition

操作

所使用的三种方法既将插入并读取单个记录。

重要的是:

  • Dapper和EF Core需要更少的手写代码
  • dapper和sqlclient需要SQL语法的体面知识
  • ef核心,在这种情况下是使用EF Power Tools配置的,这意味着没有手动配置。
  • 哪个是个人选择

插入新的记录版本1

在以下样本中插入记录,但我们没有获得新的记录键

使用SQLClient数据提供商插入新记录

插入新记录。

  • 使用连接字符串创建连接对象
  • 创建命令对象
  • 添加一个参数
  • 打开连接
  • 执行命令
public static void InsertImage(byte[] imageBytes)
{
    var sql = "INSERT INTO [dbo].[Pictures1] ([Photo])  VALUES (@ByteArray)";

    using var cn = new SqlConnection(ConnectionString());
    using var cmd = new SqlCommand(sql, cn);

    cmd.Parameters.Add("@ByteArray", SqlDbType.VarBinary).Value = imageBytes;

    cn.Open();
    cmd.ExecuteNonQuery();
}

与Dapper插入新记录

  • 使用连接字符串创建连接对象
  • 添加一个参数
  • 执行命令
public static void InsertImage(byte[] imageBytes)
{

    var sql = "INSERT INTO [dbo].[Pictures1] ([Photo])  VALUES (@ByteArray)";

    using var cn = new SqlConnection(ConnectionString());
    var parameters = new { ByteArray = imageBytes};
    cn.Execute(sql, parameters);

}

用EF Core 7插入新记录

  • 创建DBContext的实例
  • 创建一个类型的实例
  • 保存更改
public static void InsertImage(byte[] imageBytes)
{

    using var context = new Context();
    context.Add(new Pictures() { Photo = imageBytes });
    context.SaveChanges();

}

插入新的记录版本2

在以下样本中,使用新记录主键

插入记录

sqlclient

我们将SELECT CAST(scope_identity() AS int)附加到插入物,而不是ExecuteNonQuery使用返回对象的ExecuteScalar,我们将其铸造为与主键相同的类型。

public static void InsertImage(byte[] imageBytes)
{
    var sql = 
        """
        INSERT INTO [dbo].[Pictures1] ([Photo])  VALUES (@ByteArray);
        SELECT CAST(scope_identity() AS int);
        """;

    using var cn = new SqlConnection(ConnectionString());
    using var cmd = new SqlCommand(sql, cn);

    cmd.Parameters.Add("@ByteArray", SqlDbType.VarBinary).Value = imageBytes;

    cn.Open();
    var key = (int)cmd.ExecuteScalar();
}

Dapper

以下OUTPUT Inserted.Id添加到SQL中,注意Id需要匹配主密钥名称。

而不是Execute方法,我们使用的ExecuteScalar基本上与sqlclient相同。

public static void InsertImage(byte[] imageBytes)
{

    var sql = "INSERT INTO [dbo].[Pictures1] ([Photo]) OUTPUT Inserted.Id VALUES (@ByteArray)  ";

    using var cn = new SqlConnection(ConnectionString());
    var parameters = new { ByteArray = imageBytes};
    var key = (int)cn.ExecuteScalar(sql, parameters);

}

EF核心

只需将图片对象移至变量即可。在Savechanges之后,photoContainer.Id将具有新的主键。

public static void InsertImage(byte[] imageBytes)
{

    using var context = new Context();

    var photoContainer = new Pictures() { Photo = imageBytes };
    context.Add(photoContainer);
    context.SaveChanges();

}

阅读图像

您会注意到的是,在这三种方法之间,它们实际上是相同的。

使用EF核心,还有一些额外的行与返回类型保持同步,以使其他两种方法。

SQLClient具有比其他两种方法多几行代码。

sqlclient

public static (PhotoContainer container, bool success) ReadImage(int identifier)
{
    var photoContainer = new PhotoContainer() { Id = identifier };
    var sql = "SELECT id, Photo FROM dbo.Pictures1 WHERE dbo.Pictures1.id = @id;";

    using var cn = new SqlConnection(ConnectionString());
    using var cmd = new SqlCommand(sql, cn);

    cmd.Parameters.Add("@Id", SqlDbType.Int).Value = identifier;

    cn.Open();

    var reader = cmd.ExecuteReader();
    reader.Read();

    if (!reader.HasRows)
    {
        return (null, false);
    }

    var imageData = (byte[])reader[1];
    using (var ms = new MemoryStream(imageData, 0, imageData.Length))
    {
        ms.Write(imageData, 0, imageData.Length);
        photoContainer.Picture = Image.FromStream(ms, true);
    }

    return (photoContainer, true);
}

dapper

public static (PhotoContainer container, bool success) ReadImage(int identifier)
{

    var photoContainer = new PhotoContainer() { Id = identifier };
    var sql = "SELECT id, Photo FROM dbo.Pictures1 WHERE dbo.Pictures1.id = @id";

    using var cn = new SqlConnection(ConnectionString());
    var parameters = new { id = identifier };
    var container = cn.QueryFirstOrDefault<ImageContainer>(sql, parameters);

    if (container is null)
    {
        return (null, false);
    }

    var imageData = container.Photo;

    using (var ms = new MemoryStream(imageData, 0, imageData.Length))
    {
        ms.Write(imageData, 0, imageData.Length);
        photoContainer.Picture = Image.FromStream(ms, true);
    }

    return (photoContainer, true);
}

ef core

public static (PhotoContainer container, bool success) ReadImage(int identifier)
{
    var photoContainer = new PhotoContainer() { Id = identifier };
    using var context = new Context();

    var item = context.Pictures1.FirstOrDefault(item => item.Id == identifier);

    if (item is null)
    {
        return (null, false);
    }

    var imageData = item.Photo;

    using (var ms = new MemoryStream(imageData, 0, imageData.Length))
    {
        ms.Write(imageData, 0, imageData.Length);
        photoContainer.Picture = Image.FromStream(ms, true);
    }

    return (photoContainer, true);

}

注意
由于代码正确编写,因此在任何代码中都没有例外处理,这不会通过任何方式实施您的代码中的异常处理,因为许多事情可能会出错,因此请实施异常处理

准备项目运行

使用文件夹脚本下的脚本,创建数据库,创建单个表并填充。

为什么您是Windows表单项目?

使用Windows表单项目绕过诸如Securty问题之类的事物,并且非常易于阅读和理解。

源代码

克隆以下GitHub repository