You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# WPF+SQL Server LocalDB项目如何制作可正常运行的安装向导?

问题描述

开发了基于.NET 6.0的C# WPF自行车店数据库界面应用,使用SQL Server LocalDB,核心功能为两张表的CRUD操作及DataGrid展示。通过NuGet的Scaffold-DbContext生成了Order、Warehouse实体类及BikeStoresContext上下文类。

在Visual Studio 2022中运行正常,但用Advanced Installer生成的.exe文件操作数据库时,程序冻结并崩溃。尝试过Inno Setup、Visual Studio安装项目、Advanced Installer等工具制作安装向导,也尝试将BIkeStores.mdf和BIkeStores.Idf文件加入项目,均无法解决问题。不清楚如何正确将数据库文件与项目绑定,使应用在用户电脑上正常运行。


Order.cs

using System;
using System.Collections.Generic;

namespace BikeStore;

public partial class Order
{
    public int Id { get; set; }

    public string? CustomerName { get; set; }
    public string? CustomerSurname { get; set; }
    public string? PhoneNumber { get; set; }
    public string? Email { get; set; }
    public string? ResidentialAddress { get; set; }

    public string? BikeCategory { get; set; }
    public string? BikeBrand { get; set; }
    public string? BikeModel { get; set; }

    public string? EmployeeName { get; set; }
    public string? EmployeeSurname { get; set; }
}

Warehouse.cs

using System;
using System.Collections.Generic;

namespace BikeStore;

public partial class Warehouse
{
    public int Id { get; set; }

    public string? ItemName { get; set; }
    public string? ItemBrand { get; set; }
    public string? ItemModel { get; set; }

    public int? ItemQuantity { get; set; }

    public string? DateOfReceipt { get; set; }
    public string? WarehouseName { get; set; }
    public string? EmployeeName { get; set; }
    public string? EmployeeSurname { get; set; }
}

BikeStoresContext.cs

using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;

namespace BikeStore;

public partial class BikeStoresContext : DbContext
{
    public BikeStoresContext()
    {
    }

    public DbSet<Order> Orders { get; set; }
    public DbSet<Warehouse> Warehouses { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder.UseSqlServer("Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=BIkeStores;Integrated Security=True;Trust Server Certificate=True;");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Order>(entity =>
        {
            entity.HasNoKey();

            entity.Property(e => e.BikeBrand)
                .IsUnicode(false)
                .HasColumnName("bike_brand");
            entity.Property(e => e.BikeCategory)
                .IsUnicode(false)
                .HasColumnName("bike_category");
            entity.Property(e => e.BikeModel)
                .IsUnicode(false)
                .HasColumnName("bike_model");
            entity.Property(e => e.CustomerName)
                .HasMaxLength(255)
                .IsUnicode(false)
                .HasColumnName("customer_name");
            entity.Property(e => e.CustomerSurname)
                .HasMaxLength(255)
                .IsUnicode(false)
                .HasColumnName("customer_surname");
            entity.Property(e => e.Email)
                .HasMaxLength(255)
                .IsUnicode(false)
                .HasColumnName("email");
            entity.Property(e => e.EmployeeName)
                .HasMaxLength(255)
                .IsUnicode(false)
                .HasColumnName("employee_name");
            entity.Property(e => e.EmployeeSurname)
                .HasMaxLength(255)
                .IsUnicode(false)
                .HasColumnName("employee_surname");
            entity.Property(e => e.Id)
                .ValueGeneratedOnAdd()
                .HasColumnName("id");
            entity.Property(e => e.PhoneNumber)
                .HasMaxLength(100)
                .IsUnicode(false)
                .HasColumnName("phone_number");
            entity.Property(e => e.ResidentialAddress)
                .HasMaxLength(255)
                .IsUnicode(false)
                .HasColumnName("residential_address");
        });

        modelBuilder.Entity<Warehouse>(entity =>
        {
            entity
                .HasNoKey()
                .ToTable("Warehouse");

            entity.Property(e => e.DateOfReceipt)
                .HasMaxLength(255)
                .IsUnicode(false)
                .HasColumnName("date_of_receipt");
            entity.Property(e => e.EmployeeName)
                .HasMaxLength(255)
                .IsUnicode(false)
                .HasColumnName("employee_name");
            entity.Property(e => e.EmployeeSurname)
                .HasMaxLength(255)
                .IsUnicode(false)
                .HasColumnName("employee_surname");
            entity.Property(e => e.Id)
                .ValueGeneratedOnAdd()
                .HasColumnName("id");
            entity.Property(e => e.ItemBrand)
                .IsUnicode(false)
                .HasColumnName("item_brand");
            entity.Property(e => e.ItemModel)
                .IsUnicode(false)
                .HasColumnName("item_model");
            entity.Property(e => e.ItemName)
                .IsUnicode(false)
                .HasColumnName("item_name");
            entity.Property(e => e.ItemQuantity).HasColumnName("item_quantity");
            entity.Property(e => e.WarehouseName)
                .IsUnicode(false)
                .HasColumnName("warehouse_name");
        });

        OnModelCreatingPartial(modelBuilder);
    }

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

DataGrid加载数据代码

public List<Order> MyOrders { get; set; }

public ObserveOrders()
{
    InitializeComponent();

    using (BikeStoresContext _context = new BikeStoresContext())
    {
        MyOrders = _context.Orders.ToList();
    }

    ordersDataGrid.ItemsSource = MyOrders;
}

项目中使用的连接字符串

SqlConnection con = new SqlConnection("Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=BIkeStores;Integrated Security=True;Trust Server Certificate=True;");

解决方案

1. 修正LocalDB部署核心问题

SQL Server LocalDB并非Windows默认组件,且你当前的连接字符串指向开发机专属的LocalDB实例,用户电脑无对应数据库。需从两方面调整:

  • 将数据库文件作为应用资源部署,动态指向应用目录下的数据库
  • 确保安装包包含LocalDB运行时,或引导用户安装

2. 修改数据库连接配置

步骤1:设置数据库文件属性

在Visual Studio中添加BIkeStores.mdf和BIkeStores.ldf后,修改文件属性:

  • 复制到输出目录:选择「如果较新则复制」
  • 生成操作:选择「内容」

步骤2:动态生成连接字符串

替换硬编码的连接字符串,改为指向应用安装目录:

// 在BikeStoresContext中修改OnConfiguring方法
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    string dbPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "BIkeStores.mdf");
    string connectionString = $"Data Source=(localdb)\\MSSQLLocalDB;AttachDbFilename={dbPath};Integrated Security=True;Trust Server Certificate=True;";
    optionsBuilder.UseSqlServer(connectionString);
}

同步更新直接使用SqlConnection的代码:

string dbPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "BIkeStores.mdf");
SqlConnection con = new SqlConnection($"Data Source=(localdb)\\MSSQLLocalDB;AttachDbFilename={dbPath};Integrated Security=True;Trust Server Certificate=True;");

3. 安装包配置(以Advanced Installer为例)

  • 添加数据库文件:将输出目录中的BIkeStores.mdf和BIkeStores.ldf添加到安装项目的[AppDir]目录
  • 包含LocalDB运行时:在「Prerequisites」中勾选对应版本的SQL Server LocalDB,设置为「在线下载」或包含本地安装包,确保用户电脑自动安装LocalDB
  • 配置权限:为[AppDir]目录添加Users组的读写权限,避免数据库文件无法写入

4. 数据库初始化处理

首次运行时确保数据库正常可用:

  • 添加启动检查逻辑,若数据库文件不存在则从备份模板复制,或执行SQL脚本创建表结构
  • 建议使用空白数据库模板,避免直接复制开发机的数据库文件(可能包含冗余数据或权限问题)

5. 崩溃调试

添加全局异常捕获,生成错误日志定位问题:

// 在App.xaml.cs的OnStartup方法中添加
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
{
    string logPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "error.log");
    File.WriteAllText(logPath, e.ExceptionObject.ToString());
};

用户运行崩溃后,查看error.log即可明确原因(如LocalDB未安装、路径错误、权限不足等)


内容的提问来源于stack exchange,提问作者75-73-65-72-6E-61-6D-65

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 19:17:34