Lightswitch: 处理视图





5.00/5 (5投票s)
在这里,我将解释如何在 Lightswitch 中使用 SQL 视图,以及如何将数据保存到基于视图创建的屏幕上。
引言
在本文中,我将讨论如何创建一个浏览屏幕,其底层数据来自一个表,以及如何创建一个编辑屏幕,其底层数据来自一个视图。那么,下一个问题就出现了,在保存数据时,保存工作流程将如何工作?因为如果你知道 Lightswitch 的工作原理,你一定会理解我在这里要解决的问题。对于那些不知道的人来说,编辑和保存工作流程是通过我们创建浏览屏幕的表来工作的。但在我们的案例中,你将如何实现这个场景。
背景
嗯,从技术上讲,我不想在这里详细解释。你可以回顾一下 Lightswitch 的基础知识。它非常简单。由于这是一篇高级文章,我将直接进入问题陈述。
我使用的是 Visual Studio Lightswitch 2013 项目,并使用 SQL Server Management Studio 2013。我有一个名为 tblFamily
的表,其 create
语句大致如下
CREATE TABLE [dbo].[tblFamily](
[FamilyID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[FamilyTypeID] [int] NOT NULL,
[Name] [varchar](100) NOT NULL,
[OffsetFromMaxAsAtDate] [tinyint] NULL DEFAULT ((1)),
[TimeDataExpires] [time](7) NULL,
[ExcludeZeroNumberOfUnits] [bit] NOT NULL DEFAULT ((1)),
[PrefilterConstituents] [bit] NULL DEFAULT ((0)),
[LimitEndDate] [bit] NOT NULL DEFAULT ((0)),
[IgnoreForPricing] [bit] NOT NULL DEFAULT ((0)),
[AutoAddOddLots] [bit] NULL DEFAULT ((0)),[AutoAddMissingListing] [bit] NOT NULL DEFAULT ((0)),
CONSTRAINT [PK_tblFamily] PRIMARY KEY CLUSTERED ( [FamilyID] ASC)
) ON [PRIMARY]
有了这个表,我将创建我的浏览屏幕。最值得关注的是 TimeDataExpires
属性,它的数据类型是 time
。
现在,为了创建一个视图,我将这样做。稍后我将在文章中解释为什么我要创建这个视图以及它的目的是什么。在这个视图中,我将 TimeDataExpires
强制转换为 string
数据类型。
CREATE view [dbo].[vwFamilyProcessData]
as
select FamilyID,
OffsetFromMaxAsAtDate as OffsetFromMaxAsAtDate,
ExcludeZeroNumberOfUnits as ExcludeZeroNumberOfUnits,
PrefilterConstituents as PrefilterConstituents,
LimitEndDate as LimitEndDate,
IgnoreForPricing as IgnoreForPricing,
AutoAddMissingListing as AutoAddMissingListing,
AutoAddOddLots as AutoAddOddLots,
cast(TimeDataExpires as varchar(20)) as TimeDataExpires
from tblFamily
Using the Code
创建一个新的 lightswitch
项目。创建一个浏览屏幕,屏幕数据为 tblFamilies
(所有实体都将显示为复数 - 实体框架的概念)。还可以创建一个按钮来编辑这些数据。因此,选择 tblFamilies.editSelected
并导航到一个新屏幕,然后单击“确定”。你的屏幕布局应该如下所示。请忽略隐藏的按钮,我稍后会解释。
现在点击 Edittbl
Family 按钮。并尝试编辑 Time Data Expires 字段。尝试编辑此字段时,它将自动关闭编辑屏幕。无论如何,你都无法编辑此屏幕。你也可以尝试在浏览屏幕上查看这些数据,方法是将你的屏幕布局如下所示
此外,如果你在浏览器中运行此屏幕,你会注意到 Time Data Expires 属性没有数据被渲染。
因此,为了解决这个问题,我们将使用视图来渲染屏幕上的这个属性。现在创建一个“添加/编辑详细信息”屏幕,屏幕数据为 vwFamilyProcessData
,然后单击“确定”。将创建一个带有编辑对话框的屏幕,如下图所示
注意:请忽略其中的额外字段。它们是我视图的一部分。
现在返回“浏览家庭”屏幕,并添加一个按钮,如下图所示。创建按钮时,不要选择任何现有方法。而是选择“编写自己的方法”,并将方法名称命名为 SaveFamilyProcessData
。
右键单击“Save Family Process Data”按钮。选择“编辑执行代码”。添加以下几行代码
myapp.BrowseFamily.SaveFamilyProcessData_execute = function (screen) {
myapp.showEditvwFamilyProcessData(screen.vwFamilyProcessData, {
afterClosed: function (addEditScreen, navigationAction) {
if (navigationAction === msls.NavigateBackAction.commit) {
screen.tblFamilies.refresh();
}
}
});
};
myapp.BrowseFamily.SaveFamilyProcessData_execute
我们可以指定在点击 SaveFamilyProcessData
按钮时可以执行的操作。
myapp.showEditvwFamilyProcessData()
指定在点击 SaveFamilyProcessData
按钮时,打开 EditvwFamilyProcessData
屏幕。我们将 screen.vwFamilyProcessData
作为第一个参数传递,因为这指定了需要在该屏幕上显示哪些数据。如果你不传递任何内容,它将打开一个带有空白字段的 EditvwFamilyProcessData
屏幕。值得庆幸的是,Lightswitch 会自动识别选定的 FamilyID
,并在编辑屏幕上显示该数据。我们不必为此操心。
我们已经添加了 afterClosed
处理程序,以便在成功保存操作后刷新屏幕。我们需要手动添加这段代码,因为在我们的保存操作之后,基本屏幕不会自动刷新。
现在主要问题来了。如何从视图保存数据。既然我已经为你解决了这个问题,所以现在看起来会非常容易。但请相信我,我花了两个多星期才解决这个问题。
转到服务器项目,然后在“数据源”下双击 vwFamilyProcessData.Isml 文件。
现在转到“编写代码”,然后选择“更新”方法。请参考下图
添加这段代码
partial void vwFamilyProcessDatas_Updating(vwFamilyProcessData entity)
{
if(entity.Details.EntityState.ToString() == "Modified")
{
var AutoAddMissingListing = entity.AutoAddMissingListing;
var AutoAddOddLots = entity.AutoAddOddLots;
var DefaultFilterValue = entity.DefaultFilterValue;
var ExcludeZeroNumberOfUnits = entity.ExcludeZeroNumberOfUnits;
var IgnoreForPricing = entity.IgnoreForPricing;
var LimitEndDate = entity.LimitEndDate;
var OffsetFromMaxAsAtDate = entity.OffsetFromMaxAsAtDate;
var PrefilterConstituents = entity.PrefilterConstituents;
var TimeDataExpires = entity.TimeDataExpires;
tblFamily objFamily = tblFamilies.Where(f => f.FamilyID == entity.FamilyID).Single();
objFamily.AutoAddMissingListing = AutoAddMissingListing;
objFamily.AutoAddOddLots = AutoAddOddLots;
objFamily.DefaultFilterValue = DefaultFilterValue;
objFamily.ExcludeZeroNumberOfUnits = ExcludeZeroNumberOfUnits;
objFamily.IgnoreForPricing = IgnoreForPricing;
objFamily.LimitEndDate = LimitEndDate;
objFamily.OffsetFromMaxAsAtDate = OffsetFromMaxAsAtDate;
objFamily.PrefilterConstituents = PrefilterConstituents;
objFamily.TimeDataExpires = TimeSpan.Parse(TimeDataExpires);
entity.Details.DiscardChanges();
}
}
我将尝试解释这段代码。Lightswitch 遵循一个保存管道流程。它遵循一套特定的规则,并始终遵循相同的管道。保存管道是每个 LightSwitch 应用程序自动生成的。因此,理解这个概念非常重要。
有关该概念的详细信息,请参阅 这篇文章。
Lightswitch 会按照屏幕上可见的顺序调用“编写代码”部分中列出的通用方法。而且,由于我们试图编辑屏幕上已填充的数据,因此使用 Updating
方法更有意义。
Updating
方法将在 vwFamilyProcessData
创建的添加/编辑屏幕发生更改时被调用。因此,当我们打开 EditvwFamilyProcessData
屏幕并尝试在该屏幕上编辑数据时,Lightswitch 会捕获此更改,并将更改后的数据包含到保存管道中。
因此,类型为 vwFamilyProcessData
的实体捕获了屏幕上的所有数据。通过这行代码 `if(entity.Details.EntityState.ToString() == "Modified"
)`,我们检查实体是否已被修改。如果 EntityState
是 Modified
,则会进入 if
循环。我们将屏幕上的所有数据捕获到局部变量中。然后,我们使用正在编辑的 FamilyID
加载 Family 详细信息,并将值存储在 tblFamily
对象 objFamily
中。
现在到了棘手的部分。请注意,我已对实体执行了“丢弃更改”。我不得不这样做,因为 Lightswitch 将 TimeDataExpires
属性理解为计算属性或派生属性。请参考下图
而且,如果你仔细想想,这是有道理的。在视图中,TimeDataExpires
的数据类型是 string
,而在 tblFamily
(实际表)中,数据类型是 Time
。由于存在数据类型不匹配,Lightswitch 自然不允许数据保存。如果没有数据类型不匹配,Lightswitch 就会成功保存这些数据。
因此,我们必须丢弃 vwFamilyProcessData
实体所做的更改,并保存 tblFamily
实体所做的更改。Lightswitch 会捕获 tblFamily
有一些更改的信息,并在保存管道中处理这些信息。因此,数据将直接为特定的 FamilyID
保存到 tblFamily
表中。
执行“全部保存”并尝试在浏览器中运行项目。选择一个家庭,然后通过单击“Save Family Process Data”按钮尝试对其进行编辑。EditvwFamilyProcessData
屏幕将出现,并填充所选 FamilyID
的数据。尝试在屏幕上编辑任何数据,然后单击顶部的“保存”按钮。编辑屏幕将在成功保存操作后关闭,屏幕也将刷新,因为我们在 afterClosed
处理程序中添加了代码。
非常非常非常重要的注意:请不要删除我们最先创建的按钮,即 Edittbl
Family 按钮。此按钮用于在 Browse Family 屏幕的页面加载时以某种方式绑定你的数据。如果删除了此按钮,当你第一次尝试单击“Save Family Process Data”按钮时,它会弹出一个空白的弹出窗口。关闭弹出窗口后,如果你再次单击 SaveFamilyProcessData 按钮并尝试第二次打开弹出屏幕,它将成功加载你的数据。因此,为了避免此问题,请不要删除 Edittbl Family 按钮,而是通过取消选中按钮的 IsVisible 属性将其设置为不可见。请参考下图