【问题标题】:Project structure for EF/Silverlight applicationEF/Silverlight 应用程序的项目结构
【发布时间】:2012-05-14 12:35:43
【问题描述】:

我目前正在为 3 层解决方案寻找一个良好的项目结构,以避免在新项目中进行不必要的工作。

该项目将包含一个核心产品,该产品具有

  • 包含 EF 代码优先模型的模型项目
  • 在服务器上有业务逻辑和通信逻辑的项目
  • 客户端上的存储库项目
  • 带有视图和视图模型的silverlight 项目(希望在此处使用 caliburn.micro)

现在的问题是,客户可能有一些特殊要求,可能会导致上述所有项目发生变化。所以我的想法是我可以只使用基本结构并为客户创建相同的结构。如果没有更改,我将只有空类,它们只是扩展基类而不添加任何内容。

这给我带来了以下问题:

  • 实体框架(代码优先)在一个项目中拥有基类(已经具备完整功能)而在另一个项目中使用新字段扩展模型类是否存在问题?
  • 在 XAML 中更改用户控件是否存在问题?例如,如果我的核心中有一个包含五个文本框的用户控件,并且我想将第二个框更改为单选按钮,但没有其他内容。

如果有更好的方法来处理客户特定的更改,我也会接受对项目结构的更改。

编辑:我可能会使用以下方法来解决问题。

实体框架:

首先使用代码,似乎可以让一个模型项目扩展另一个项目。这意味着我可以写如下内容:

public class CoreAddress{
  [Key]
  public int AdrId{get; set;}
  public string Street {get;set;}
}

public class CustomerAddress : CoreAddress{
  public string StreetNumber {get; set;}
}

唯一需要做的就是 DbContext 中的一行:

(this as IObjectContextAdapter).ObjectContext.MetadataWorkspace.LoadFromAssembly(typeof(<entity from other assembly>).Assembly);

XAML

为了在 XAML 中获得类似的行为,我必须使用 Caliburn.Micro(与 MEF 结合使用),这在此处很有帮助。

我将创建包含 ContentControl 元素的用户控件,这些元素是使用 MEF 动态获取的。这意味着我又拥有了一个包含所有视图和 ViewModel 的核心项目。如果我需要在某处为客户交换特殊控件,我将控件更改为 ContentControl 并为其创建核心视图和 ViewModel(与更改请求之前相同)。 ContentControl 的这个 ViewModel 带有一个导出接口和 ExportMetadata 以设置优先级 1。 现在,我使用另一个 UserControl 创建另一个项目,该项目具有其他一些控件而不是核心控件,并再次将其注释为具有相同界面的导出,但将我的优先级设置为更高,因此加载了客户特定的控件。

简短的例子:

主要用户控件和视图模型:

<UserControl x:Class="SilverlightApplication5.TestView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel>
            <ContentControl x:Name="Item"/>
            <TextBox x:Name="TextItem" Text="asdf"/>
        </StackPanel>

    </Grid>
</UserControl>

public class TestViewModel : Screen
    {
        private object viewModel;
        private Lazy<IMyViewModel, IPluginMetadata>[] _orderEditorFactory;

        [ImportMany(typeof(IMyViewModel), AllowRecomposition = true)]
        public Lazy<IMyViewModel, IPluginMetadata>[] OrderEditorFactory
        {
            get { return _orderEditorFactory; }
            set
            {
                _orderEditorFactory = value;
                Item = _orderEditorFactory.OrderByDescending(lazy => lazy.Metadata.Priority).First().Value;

            }
        }
    private object _item;

        public object Item
        {
            get { return _item; }
            set
            {
                _item = value;
                NotifyOfPropertyChange(() => Item);
            }
        }
    }

核心控制:

<UserControl x:Class="SilverlightClassLibrary2.MainControlView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <StackPanel>
        <TextBlock x:Name="Test" Text="Text from Core control"/>
    </StackPanel>
</UserControl>

[Export(typeof (IMyViewModel))]
[ExportMetadata("Name", "Pluginc")]
[ExportMetadata("Priority", 30)]
public class MainControlViewModel : Screen, IHarnessAware, IMyViewModel
{

}

客户特定的控制:

<UserControl x:Class="SilverlightClassLibrary1.CustomView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <RadioButton x:Name="Test" Content="{Binding Path=Test}"/>
    </Grid>
</UserControl>

[Export(typeof(IMyViewModel))]
[ExportMetadata("Name", "Plugind")]
[ExportMetadata("Priority", 2)]
public class CustomViewModel : MainControlViewModel, IHarnessAware, IMyViewModel
{
}

导出界面:

public interface IMyViewModel
{

}

导出元数据接口:

   public interface 
        IPluginMetadata
    {
        string Name { get; }
        [DefaultValue(0)]
        int Priority { get; }
    }

我确实用这个来回答这个问题,因为我仍然对可能已经解决了类似问题的其他人的意见感兴趣。

【问题讨论】:

  • 您似乎想要一个基础项目,您可以根据每个客户应用一些更改。我做对了吗?
  • 我想拥有一个(多个)核心项目,为每个客户提供(拥有)代码,我还想拥有只属于一个客户的专业项目。

标签: entity-framework xaml design-patterns project-structure


【解决方案1】:

关于项目结构: 您可以创建一个基础项目,其中包含您需要的每个关注层。模型、业务、视图、存储库等。

还可以创建一些基本流程,例如,将其控制器连接到存储库的单个视图。将其保存在您的代码库中,然后在您需要创建新项目时将其分叉。

现在,您无需花费时间进行设置,而是需要一些时间来根据项目需要进行自定义。

关于 XAML: 恕我直言,如果您更改组件,您应该确保它返回的数据类型与您的控件期望的相同。如果您将文本框换成复选框,请确保检查将字符串返回给控制器。

【讨论】:

  • 这个解决方案听起来不太适合客户的特定更改。问题是,如果我有 100 个客户,我为所有客户创建一个分支,然后我在核心中发现一个重大错误,我将不得不将此修复应用到所有客户。
  • 我想到了其他背景。这不是一个简单的问题,正如您所说的客户可能有一些特殊要求,可能导致上述所有项目发生变化。这意味着自定义没有保存任何内容。您可以尝试隔离可被您应用的所有自定义实例重用的核心功能。
  • 由于没有其他答案,我会给你赏金。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-13
  • 1970-01-01
  • 2012-01-02
  • 1970-01-01
  • 2014-11-13
  • 2014-01-10
  • 1970-01-01
相关资源
最近更新 更多