使用实体模型和 LINQ 的 C# WPF SQL 多表 CRUD
Posted
技术标签:
【中文标题】使用实体模型和 LINQ 的 C# WPF SQL 多表 CRUD【英文标题】:C# WPF SQL multi-table CRUD using Entity Model and LINQ 【发布时间】:2020-04-15 19:55:07 【问题描述】:我正在尝试使用实体模型将多个 SQL 表显示到数据网格以及更新、创建和删除行。在我加入实体模型对象后,我在从表中获取实体模型对象时遇到问题,因为现在实体的数据字段比它来自的原始模型对象多。我希望解决方案存在于某种 ViewModel 中,但是我无法弄清楚如何将对象从 ViewModel 中分离出来。几天来我一直在尝试解决这个问题,此时我希望我必须对我的代码进行一些认真的重组。任何提示将不胜感激。
这是负载实体模型(负载与货物负载有关,这与装载任何东西没有关系)
public partial class Load
public int bol_num get; set;
public string pro_num get; set;
public string quote_num get; set;
public string ref_num get; set;
public Nullable<double> weight get; set;
public Nullable<int> pieces get; set;
public string commodity get; set;
public Nullable<double> mileage get; set;
public Nullable<decimal> carrier_rate get; set;
public Nullable<decimal> customer_rate get; set;
public Nullable<int> driver_id get; set;
public Nullable<int> dispatch_id get; set;
public Nullable<int> customer_id get; set;
public Nullable<int> broker_id get; set;
public Nullable<System.DateTime> pick_date get; set;
public Nullable<System.TimeSpan> pick_time get; set;
public Nullable<System.DateTime> drop_date get; set;
public Nullable<System.TimeSpan> drop_time get; set;
public Nullable<System.DateTime> last_updated_time get; set;
public string load_status get; set;
public Nullable<int> account_id get; set;
public virtual Account Account get; set;
//Constructors
public Load(
int bolInt,
string proString,
string quoteString,
string refString,
double weightDouble,
int piecesInt,
string commodityString,
double mileageDouble,
decimal carrier_rateDecimal,
decimal customer_rateDecimal,
int driver_idInt,
int dispatch_idInt,
int customer_idInt,
int broker_idInt,
DateTime pick_dateDateTime,
TimeSpan pick_timeTimeSpan,
DateTime drop_dateDateTime,
TimeSpan drop_timeTimeSpan,
DateTime last_updated_timeDateTime,
string load_statusString,
int account_idInt
)
bol_num = bolInt;
pro_num = proString;
quote_num = quoteString;
ref_num = refString;
weight = weightDouble;
pieces = piecesInt;
commodity = commodityString;
mileage = mileageDouble;
carrier_rate = carrier_rateDecimal;
customer_rate = customer_rateDecimal;
driver_id = driver_idInt;
dispatch_id = dispatch_idInt;
customer_id = customer_idInt;
broker_id = broker_idInt;
pick_date = pick_dateDateTime;
pick_time = pick_timeTimeSpan;
drop_date = drop_dateDateTime;
drop_time = drop_timeTimeSpan;
last_updated_time = last_updated_timeDateTime;
load_status = load_statusString;
account_id = account_idInt;
//Default
public Load()
这是联系人对象的实体模型
public partial class Contact
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Contact()
this.Accounts = new HashSet<Account>();
this.Users = new HashSet<User>();
public int id get; set;
public string contact_name get; set;
public string contact_phone get; set;
public string contact_email get; set;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Account> Accounts get; set;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<User> Users get; set;
这是处理添加新行和更新现有行的函数
//Update or Create Button
private void update_btn_Click(object sender, RoutedEventArgs e)
//Value Setting process
try
//Load model
Load loadModel = new Load();
//Get the load data from input fields
loadModel.bol_num = Convert.ToInt32(bol_txt.Text.Trim());
loadModel.load_status = loadStatus_cmbo.Text;
loadModel.pro_num = pro_txt.Text.Trim();
loadModel.quote_num = quote_txt.Text.Trim();
loadModel.ref_num = ref_txt.Text.Trim();
try
loadModel.weight = Convert.ToDouble(weight_txt.Text.Trim());
catch (System.FormatException ex) MessageBox.Show(ex.Message, "Invalid Pieces Entry", MessageBoxButton.OK, MessageBoxImage.Error);
try
loadModel.pieces = Convert.ToInt32(pieces_txt.Text.Trim());
catch(System.FormatException ex)MessageBox.Show(ex.Message, "Invalid Pieces Entry", MessageBoxButton.OK, MessageBoxImage.Error);
loadModel.commodity = commodity_txt.Text.Trim();
loadModel.mileage = Convert.ToDouble(mileage_txt.Text.Trim());
loadModel.carrier_rate = Convert.ToDecimal(carrierRate_txt.Text.Trim());
loadModel.customer_rate = Convert.ToDecimal(customerRate_txt.Text.Trim());
//Pick Date & Time setter
loadModel.pick_date = pickDate_picker.SelectedDate.Value;
loadModel.pick_time = TimeSpanBuilder(pickAptTime_txt.Text);
//Drop Date & Time setter
loadModel.drop_date = dropDate_picker.SelectedDate.Value;
loadModel.drop_time = TimeSpanBuilder(dropAptTime_txt.Text);
loadModel.driver_id = Convert.ToInt32(driver_txt.Text.Trim());
loadModel.dispatch_id = Convert.ToInt32(dispatch_txt.Text.Trim());
loadModel.customer_id = Convert.ToInt32(customer_txt.Text.Trim());
loadModel.broker_id = Convert.ToInt32(broker_txt.Text.Trim());
//Last updated
loadModel.last_updated_time = DateTime.Now;
//Save the load to the database
using(HOTLOADDBEntities HOTLOADEntity = new HOTLOADDBEntities())
if(loadModel.bol_num == 0)//Insert
HOTLOADEntity.Loads.Add(loadModel);
Clear();
MessageBox.Show("Saved Succesfully");
else//Update
HOTLOADEntity.Entry(loadModel).State = EntityState.Modified;
Clear();
//Save the changes
HOTLOADEntity.SaveChanges();
Search();
//Entity Model Exception handler
catch (DbEntityValidationException dbEx)
foreach (var validationErrors in dbEx.EntityValidationErrors)
foreach (var validationError in validationErrors.ValidationErrors)
Trace.TraceInformation(
"Class: 0, Property: 1, Error: 2",
validationErrors.Entry.Entity.GetType().FullName,
validationError.PropertyName,
validationError.ErrorMessage);
这是从 DataGrid 中选择对象的函数,由于我在我的搜索函数中添加了连接功能,该函数现在无法使用。
private void LoadBoard_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
if (LoadBoard.SelectedIndex != -1)
//Load model
Load loadModel = (Load)LoadBoard.SelectedItem;
using (HOTLOADDBEntities HOTLOADEntity = new HOTLOADDBEntities())
loadModel = HOTLOADEntity.Loads.Where(x => x.bol_num == loadModel.bol_num).FirstOrDefault();
bol_txt.Text = loadModel.bol_num.ToString();
loadStatus_cmbo.SelectedIndex = ParseStatus(loadModel.load_status);
pro_txt.Text = loadModel.pro_num.ToString();
quote_txt.Text = loadModel.quote_num.ToString();
ref_txt.Text = loadModel.ref_num.ToString();
weight_txt.Text = loadModel.weight.ToString();
pieces_txt.Text = loadModel.pieces.ToString();
commodity_txt.Text = loadModel.commodity.ToString();
mileage_txt.Text = loadModel.mileage.ToString();
carrierRate_txt.Text = loadModel.carrier_rate.ToString();
customerRate_txt.Text = loadModel.customer_rate.ToString();
//Dates & Times
pickDate_picker.Text = loadModel.pick_date.ToString();
pickAptTime_txt.Text = TimeStringBuilder(loadModel.pick_time.Value);
dropDate_picker.Text = loadModel.drop_date.ToString();
dropAptTime_txt.Text = TimeStringBuilder(loadModel.drop_time.Value);
driver_txt.Text = loadModel.driver_id.ToString();
dispatch_txt.Text = loadModel.dispatch_id.ToString();
customer_txt.Text = loadModel.customer_id.ToString();
broker_txt.Text = loadModel.broker_id.ToString();
lastUpdated_lbl.Content = "Last Updated: " + loadModel.last_updated_time;
//Change Update/New button text
update_btn.Content = "Update Load";
//Enable copy & delete buttons
delete_btn.IsEnabled = true;
copy_btn.IsEnabled = true;
这是处理数据库查询的函数
private void Search()
HOTLOADEntity = new HOTLOADDBEntities();
//Timespan handling
TimeSpan pickTimeStart = TimeSpan.Zero;
TimeSpan pickTimeEnd = TimeSpan.Zero;
TimeSpan dropTimeStart = TimeSpan.Zero;
TimeSpan dropTimeEnd = TimeSpan.Zero;
try pickTimeStart = TimeSpanBuilder(pickTimeStartSearch_txt.Text); catch (System.Exception)//Ignore
try pickTimeEnd = TimeSpanBuilder(pickTimeEndSearch_txt.Text); catch (System.Exception)//Ignore
try dropTimeStart = TimeSpanBuilder(dropTimeStartSearch_txt.Text); catch (System.Exception)//Ignore
try dropTimeEnd = TimeSpanBuilder(dropTimeEndSearch_txt.Text); catch (System.Exception)//Ignore
var matchedLoads = (
from loadsTable in HOTLOADEntity.Loads
join driversTable in HOTLOADEntity.Contacts on loadsTable.driver_id equals driversTable.id
/*
where
loadsTable.bol_num.ToString().Contains(bolSearch_txt.Text) &&
loadsTable.pro_num.ToString().Contains(proSearch_txt.Text) &&
loadsTable.quote_num.ToString().Contains(quoteSearch_txt.Text) &&
loadsTable.ref_num.ToString().Contains(refSearch_txt.Text) &&
//Pick Date search terms
((pickDateStart_dtpckr.SelectedDate == null || loadsTable.pick_date >= pickDateStart_dtpckr.SelectedDate) &&
(pickDateEnd_dtpckr.SelectedDate == null || loadsTable.pick_date <= pickDateEnd_dtpckr.SelectedDate)) &&
//Pick Time search terms
((pickTimeStartSearch_txt.Text == null || pickTimeStart == TimeSpan.Zero || loadsTable.pick_time.Value >= pickTimeStart) &&
(pickTimeEndSearch_txt.Text == null || pickTimeEnd == TimeSpan.Zero || loadsTable.pick_time.Value <= pickTimeEnd)) &&
//Drop Date Search terms
((dropDateStart_dtpckr.SelectedDate == null || loadsTable.drop_date >= dropDateStart_dtpckr.SelectedDate) &&
(dropDateEnd_dtpckr.SelectedDate == null || loadsTable.drop_date <= dropDateEnd_dtpckr.SelectedDate)) &&
//Drop Time search terms
((dropTimeStartSearch_txt.Text == null || dropTimeStart == TimeSpan.Zero || loadsTable.drop_time.Value >= dropTimeStart) &&
(dropTimeEndSearch_txt.Text == null || dropTimeEnd == TimeSpan.Zero || loadsTable.drop_time.Value <= dropTimeEnd))
*/
select new
bol_num = loadsTable.bol_num,
load_status = loadsTable.load_status,
pro_num = loadsTable.pro_num,
quote_num = loadsTable.quote_num,
ref_num = loadsTable.ref_num,
weight = loadsTable.weight,
pieces = loadsTable.pieces,
commodity = loadsTable.commodity,
mileage = loadsTable.mileage,
carrier_rate = loadsTable.carrier_rate,
customer_rate = loadsTable.customer_rate,
pick_date = loadsTable.pick_date,
pick_time = loadsTable.pick_time,
drop_date = loadsTable.drop_date,
drop_time = loadsTable.drop_time,
last_updated_time = loadsTable.last_updated_time,
driver_id = loadsTable.driver_id,
driver_name = driversTable.contact_name,
driver_phone = driversTable.contact_phone,
driver_email = driversTable.contact_email,
dispatch_id = loadsTable.dispatch_id,
customer_id = loadsTable.customer_id,
broker_id = loadsTable.broker_id,
account_id = loadsTable.account_id
).ToList();
LoadBoard.ItemsSource = matchedLoads;
不确定这是否相关,但这是 DataGrid 的关联 XAML
<DataGrid Name="LoadBoard" AutoGenerateColumns="False" AlternatingRowBackground="Cornsilk" Background="Ivory" IsReadOnly="True" MouseDoubleClick="LoadBoard_MouseDoubleClick">
<!--Datagrid Columns-->
<DataGrid.Columns>
<DataGridTextColumn x:Name="bolColumn" Header="BOL#" Binding="Binding bol_num"/>
<DataGridTextColumn x:Name="statusColumn" Header="Status" Binding="Binding load_status"/>
<DataGridTextColumn x:Name="proColumn" Header="Pro#" Binding="Binding pro_num"/>
<DataGridTextColumn x:Name="quoteColumn" Header="Quote#" Binding="Binding quote_num"/>
<DataGridTextColumn x:Name="refColumn" Header="Ref" Binding="Binding ref_num"/>
<DataGridTextColumn x:Name="weightColumn" Header="Weight" Binding="Binding weight"/>
<DataGridTextColumn x:Name="piecesColumn" Header="Pieces" Binding="Binding pieces"/>
<DataGridTextColumn x:Name="commodityColumn" Header="Commodity" Binding="Binding commodity"/>
<DataGridTextColumn x:Name="mileageColumn" Header="Mileage" Binding="Binding mileage"/>
<DataGridTextColumn x:Name="carrierColumn" Header="Carrier Rate" Binding="Binding carrier_rate"/>
<DataGridTextColumn x:Name="customerRateColumn" Header="Customer Rate" Binding="Binding customer_rate"/>
<DataGridTextColumn x:Name="pickDateColumn" Header="Pick Date" Binding="Binding pick_date, StringFormat= \0:MM/dd/yyyy\" />
<DataGridTextColumn x:Name="pickTimeColumn" Header="Pick Time" Binding="Binding pick_time, StringFormat=hh\\:mm" />
<DataGridTextColumn x:Name="dropDateColumn" Header="Drop Date" Binding="Binding drop_date, StringFormat= \0:MM/dd/yyyy\" />
<DataGridTextColumn x:Name="dropTimeColumn" Header="Drop Time" Binding="Binding drop_time, StringFormat=hh\\:mm" />
<DataGridTextColumn x:Name="lastUpdatedColumn" Header="Last Updated" Binding="Binding last_updated_time" />
<DataGridTextColumn x:Name="driverNameColumn" Header="Driver Name" Binding="Binding driver_name"/>
<DataGridTextColumn x:Name="driverPhoneColumn" Header="Driver Phone" Binding="Binding driver_phone"/>
<DataGridTextColumn x:Name="driverEmailColumn" Header="Driver Email" Binding="Binding driver_email"/>
<DataGridTextColumn x:Name="DispatchColumn" Header="Dispatch" Binding="Binding dispatch_id"/>
<DataGridTextColumn x:Name="CustomerColumn" Header="Customer" Binding="Binding customer_id"/>
<DataGridTextColumn x:Name="BrokerColumn" Header="Broker" Binding="Binding broker_id"/>
</DataGrid.Columns>
</DataGrid>
【问题讨论】:
常见的解决方案是为存储和表示级别设置单独的类,并在需要时在它们之间进行映射 我该怎么做?我尝试使用视图模型,但无法使用 CRUD 操作。 【参考方案1】:所以我最终重新尝试了 View Model 解决方案并最终让它工作。这是我以前这样做的代码。
查看模型类
class ViewModel
//Load Fields
public int bol_num get; set;
public string pro_num get; set;
public string quote_num get; set;
public string ref_num get; set;
public Nullable<double> weight get; set;
public Nullable<int> pieces get; set;
public string commodity get; set;
public Nullable<double> mileage get; set;
public Nullable<decimal> carrier_rate get; set;
public Nullable<decimal> customer_rate get; set;
public Nullable<int> driver_id get; set;
public Nullable<int> dispatch_id get; set;
public Nullable<int> customer_id get; set;
public Nullable<int> broker_id get; set;
public Nullable<System.DateTime> pick_date get; set;
public Nullable<System.TimeSpan> pick_time get; set;
public Nullable<System.DateTime> drop_date get; set;
public Nullable<System.TimeSpan> drop_time get; set;
public Nullable<System.DateTime> last_updated_time get; set;
public string load_status get; set;
public Nullable<int> account_id get; set;
//Driver Fields
public string driverContact_name get; set;
public string driverContact_phone get; set;
public string driverContact_email get; set;
修改后的搜索功能
private void Search()
HOTLOADEntity = new HOTLOADDBEntities();
//Timespan handling
TimeSpan pickTimeStart = TimeSpan.Zero;
TimeSpan pickTimeEnd = TimeSpan.Zero;
TimeSpan dropTimeStart = TimeSpan.Zero;
TimeSpan dropTimeEnd = TimeSpan.Zero;
try pickTimeStart = TimeSpanBuilder(pickTimeStartSearch_txt.Text); catch (System.Exception)//Ignore
try pickTimeEnd = TimeSpanBuilder(pickTimeEndSearch_txt.Text); catch (System.Exception)//Ignore
try dropTimeStart = TimeSpanBuilder(dropTimeStartSearch_txt.Text); catch (System.Exception)//Ignore
try dropTimeEnd = TimeSpanBuilder(dropTimeEndSearch_txt.Text); catch (System.Exception)//Ignore
var matchedLoads = (
from loads in HOTLOADEntity.Loads
join drivers in HOTLOADEntity.Contacts
on loads.driver_id equals drivers.id
where
loads.bol_num.ToString().Contains(bolSearch_txt.Text) &&
loads.pro_num.ToString().Contains(proSearch_txt.Text) &&
loads.quote_num.ToString().Contains(quoteSearch_txt.Text) &&
loads.ref_num.ToString().Contains(refSearch_txt.Text) &&
//Pick Date search terms
((pickDateStart_dtpckr.SelectedDate == null || loads.pick_date >= pickDateStart_dtpckr.SelectedDate) &&
(pickDateEnd_dtpckr.SelectedDate == null || loads.pick_date <= pickDateEnd_dtpckr.SelectedDate)) &&
//Pick Time search terms
((pickTimeStartSearch_txt.Text == null || pickTimeStart == TimeSpan.Zero || loads.pick_time.Value >= pickTimeStart) &&
(pickTimeEndSearch_txt.Text == null || pickTimeEnd == TimeSpan.Zero || loads.pick_time.Value <= pickTimeEnd)) &&
//Drop Date Search terms
((dropDateStart_dtpckr.SelectedDate == null || loads.drop_date >= dropDateStart_dtpckr.SelectedDate) &&
(dropDateEnd_dtpckr.SelectedDate == null || loads.drop_date <= dropDateEnd_dtpckr.SelectedDate)) &&
//Drop Time search terms
((dropTimeStartSearch_txt.Text == null || dropTimeStart == TimeSpan.Zero || loads.drop_time.Value >= dropTimeStart) &&
(dropTimeEndSearch_txt.Text == null || dropTimeEnd == TimeSpan.Zero || loads.drop_time.Value <= dropTimeEnd))
select new ViewModel
//Load properties
bol_num = loads.bol_num,
load_status = loads.load_status,
pro_num = loads.pro_num,
quote_num = loads.quote_num,
ref_num = loads.ref_num,
weight = loads.weight,
pieces = loads.pieces,
commodity = loads.commodity,
mileage = loads.mileage,
carrier_rate = loads.carrier_rate,
customer_rate = loads.customer_rate,
pick_date = loads.pick_date,
pick_time = loads.pick_time,
drop_date = loads.drop_date,
drop_time = loads.drop_time,
last_updated_time = loads.last_updated_time,
driver_id = loads.driver_id,
dispatch_id = loads.dispatch_id,
customer_id = loads.customer_id,
broker_id = loads.broker_id,
account_id = loads.account_id,
//Driver properties
driverContact_name = drivers.contact_name,
driverContact_phone = drivers.contact_phone,
driverContact_email = drivers.contact_email,
);
LoadBoard.ItemsSource = matchedLoads.ToList();
修改了数据网格双击按钮上的选择
private void LoadBoard_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
if (LoadBoard.SelectedIndex != -1)
//Load model
ViewModel SelectedItem = (ViewModel)LoadBoard.SelectedItem;
Load loadModel = HOTLOADEntity.Loads.Find(SelectedItem.bol_num);
using (HOTLOADDBEntities HOTLOADEntity = new HOTLOADDBEntities())
loadModel = HOTLOADEntity.Loads.Where(x => x.bol_num == loadModel.bol_num).FirstOrDefault();
bol_txt.Text = loadModel.bol_num.ToString();
loadStatus_cmbo.SelectedIndex = ParseStatus(loadModel.load_status);
pro_txt.Text = loadModel.pro_num.ToString();
quote_txt.Text = loadModel.quote_num.ToString();
ref_txt.Text = loadModel.ref_num.ToString();
weight_txt.Text = loadModel.weight.ToString();
pieces_txt.Text = loadModel.pieces.ToString();
commodity_txt.Text = loadModel.commodity.ToString();
mileage_txt.Text = loadModel.mileage.ToString();
carrierRate_txt.Text = loadModel.carrier_rate.ToString();
customerRate_txt.Text = loadModel.customer_rate.ToString();
//Dates & Times
pickDate_picker.Text = loadModel.pick_date.ToString();
pickAptTime_txt.Text = TimeStringBuilder(loadModel.pick_time.Value);
dropDate_picker.Text = loadModel.drop_date.ToString();
dropAptTime_txt.Text = TimeStringBuilder(loadModel.drop_time.Value);
driver_txt.Text = loadModel.driver_id.ToString();
dispatch_txt.Text = loadModel.dispatch_id.ToString();
customer_txt.Text = loadModel.customer_id.ToString();
broker_txt.Text = loadModel.broker_id.ToString();
lastUpdated_lbl.Content = "Last Updated: " + loadModel.last_updated_time;
//Change Update/New button text
update_btn.Content = "Update Load";
//Enable copy & delete buttons
delete_btn.IsEnabled = true;
copy_btn.IsEnabled = true;
【讨论】:
以上是关于使用实体模型和 LINQ 的 C# WPF SQL 多表 CRUD的主要内容,如果未能解决你的问题,请参考以下文章
具有 LINQ 关联的 C# 和 ADO .NET 实体数据模型以及同一表的实体
带有 LinqToSql System.Data.Linq.DuplicateKeyException 的 C# 和 SQL Server 数据库出错:无法使用已在使用的键添加实体。