Entity Framework Code First, DTO and n-tier scenario (WCF) - c#

I've read several articles about bunch of EF and DTO, and I need some clarification about using EF Code First and DTO in n-tier scenario with WCF.
Let's look a these classes:
public class Order
{
public int Id { get; set; }
public DateTime ShipDate { get; set; }
public ObservableCollection<OrderDetail> Details { get; private set; }
}
public class OrderDetail
{
public int Id { get; set; }
public int OrderId { get; set; }
public int ProductId { get; set; }
public decimal Quantity { get; set; }
}
When user want to edit existing order, my client application (WPF MVVM app) requests some DTO, which then being converted to Order instance. Then, user makes some changes in order through UI - e.g., changes ShipDate, removes two positions, modifies one, and adds one.
Now I want to deliver changes to the server. As far as I understand DTO concept, I need to construct some DTO type, containing info about changes has been made:
[DataContract]
public class UpdateOrderDTO
{
[DataMember]
public DateTime ShipDate { get; set; }
[DataMember]
public Collection<OrderDetail> NewDetails { get; private set; }
[DataMember]
public Collection<OrderDetail> ModifiedDetails { get; private set; }
[DataMember]
public Collection<OrderDetail> DeletedDetails { get; private set; }
}
But when, and where should I to create this DTO? I mean, I can't create it on submitting changes - there's no change tracking information in Order class.
Looks like, this object have to be created together with Order after it was requested for edition by user. This allows to track changes... Am I wrong?
Please note, that the question isn't about STEs. For some reasons, I don't want/can't use them in current project.
Thanks a lot for sharing your experience.

Related

How many model classes should I have entity? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I have an Article entity in my database:
public class Article
{
public Guid Id { get; set; }
public string Heading { get; set; }
public string Author { get; set; }
public string Content { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
public int ViewsCount { get; set; }
public ImageData Image { get; set; }
public IEnumerable<Comment> Comments { get; set; }
}
For the creation I have ArticleInputModel, and for displaying the details view, I have ArticleDetailsModel, and for update I have ArticleUpdateModel (etc....)
However those models have the same properties.
Should I separate this much if it means repetitions of code?
I try to follow SRP but this seems like is breaking DRY principle?
Am I overlooking something and what?
Should I separate this much if it means repetitions of code?
Usually, you can identify three situations with potentially different sets of properties when working with model classes (Data Transfer Objects; DTOs) for a single entity:
entity creation
entity reading (displaying, viewing)
entity updating
However, there may be many more subtypes — e.g. different ways to create or update an entity, partial vs. full update, various kinds of displays, e.g. full view, some kind of partial views, view of an entity in a list etc.
It does make sense to have a system in constructing DTOs, such that you differentiate between the create, read (view), update DTOs in respect to your Create, Read, Update operations. You can see a clear parallel between such DTOs and CRU(D) operations (there's typically no DTO for the Delete operation).
Regardless of the particular naming you use, such categorizations help future maintainability of your code: if, in the future, you need to introduce a property that may not be set during entity creation, but can be altered during an update, or vice versa, it is easy to do without extensive changes to unrelated parts of code, e.g. you change the updating path only, but avoid changing the creating path.
I try to follow SRP but this seems like is breaking DRY principle?
Providing the model (DTOs) classes are semantically different, then I don't see this as a violation of DRY. However, this may be subjective.
Think of DTOs as secondary objects. The primary declaration is the database entity, which is part of your data model. The various views of such an entity in the form of DTOs are dependent on this entity declaration. As long as you keep it to a simple public SomeType PropName { get; set; } in the DTOs, it is not a violation of DRY you couldn't live with. In addition, it makes sense to e.g. keep comments explaining various properties in entity declarations only, and not duplicate them into DTOs (unless you have to generate some API docs, but that's solvable with <inheritdoc/> as well). What's important, is the clear distinction between entities and DTOs and their roles.
If you're creating a new instance of an Article, what is it's Id?
Or as a more clear example, what will it's UpdatedOn date be?
How do you update something that doesn't exist yet?
One other issue you might come across very quickly is how are you going to return a list of all the articles by a particular Author?
In the Article table you should be storing Author as an Id linking as a foreign key to the Author table (assuming there can only be a single Author).
If your article table now looks like this...
public class Article
{
public Guid Id { get; set; }
public string Heading { get; set; }
public Id Author { get; set; }
public string Content { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
public int ViewsCount { get; set; }
public ImageData Image { get; set; }
public IEnumerable<Comment> Comments { get; set; }
}
...you might begin to see where separate ViewModels/DTOs come into play.
Create
public class CreateArticle
{
public string Heading { get; set; }
public IEnumerable { get; set; }
public string Content { get; set; }
public string Image { get; set; }
}
You're creating a new Article so will probably be inserting an auto generated Guid as the key. You'll also be fairly likely to be taking the current date/time as the CreatedOn date. Author would come from a lookup list of some description so you'd need to pass some sort of list into the View (simplified as IEnumerable above). The image is most likely going to be supplied from a path to the image location so you'd maybe want to display as a text box.
Add
public class AddArticle
{
public string Heading { get; set; }
public Id Author { get; set; }
public string Content { get; set; }
public ImageData Image { get; set; }
}
When you've filled in your Create form, you now want to add it to the db. In this case your DTO needs to add data in the format the db expects. So you'd now be passing the selected Author Id and maybe the ImageData after some processing magic elsewhere.
You still don't need an Article Id or CreatedOn as these will be added once this DTO has validated.
Details and View
Hopefully you're now seeing the slight differences that make the ViewModel a valuable asset. You might also require something like the following to show the details of an Article as opposed to viewing the Article itself:
public class DetailOfArticle
{
public Guid Id { get; set; }
public string Heading { get; set; }
public Author Author { get; set; }
public string Content { get; set; }
public string CreatedOn { get; set; }
public string UpdatedOn { get; set; }
public int ViewsCount { get; set; }
}
public class ViewArticle
{
public Guid Id { get; set; }
public string Heading { get; set; }
public string Author { get; set; }
public string Content { get; set; }
public string CreatedOn { get; set; }
public string UpdatedOn { get; set; }
public int ViewsCount { get; set; }
public ImageData Image { get; set; }
public IEnumerable<Comment> Comments { get; set; }
}
Notice that the details might pass in an Author entity so that you can supply more information (this could also be exploded out into separate properties). You might also want to pass the date (and/or time) as a string after formatting etc.
The Article detail probably wouldn't need the comments as it's essentially the meta-data about the Article whereas the Article view is the Article as you'd want to present it for reading.

How to use properly linq to perform efficiently a conversion from a DataTable to a set of recursive objects?

I'm working on software dealing with tests, developping using Visual Studio 2008, C#3.5. Those tests are saved into a SQLite Database, and my software is intended to process the results.
Well, there is a Information Table gathering the general information about the tests with the following columns:
LayerAName
LayerAId
LayerBName
LayerBId
LayerCName
LayerCId
LayerDName
LayerDId
Start: a DateTime to indicate when the result table has been created.
Stop: a DateTime to indicate when the result table has been modified for the last time.
ResultTableName: this table name is used for displaying the results in a DataGridView using the VirtualMode.
The layers are discriminated using their Ids and btw, from the layer A to C, the layers are behaving like containers for gathering childlayers. Only the last layer, "layerD" is linked to a Table in the Database.
public abstract class Layer
{
public String Name { get; set; }
public Int32 Id { get; set; }
public DateTime Start { get; set; }
public DateTime Stop { get; set; }
}
public class Project: Layer
{
private Int32 Id { get; set; }
public Dictionary<Int32, LayerB> As { get; set; }
}
public class LayerA : Layer
{
public Project Parent { get; set; }
public Dictionary<Int32, LayerB> Bs { get; set; }
}
public class LayerB : Layer
{
public LayerA Parent { get; set; }
public Dictionary<Int32, LayerC> Cs { get; set; }
}
public class LayerC : Layer
{
public LayerB Parent { get; set; }
public Dictionary<Int32, LayerB> Ds { get; set; }
}
public class LayerD : Layer
{
public LayerC Parent { get; set; }
public String ResultTableName { get; set; }
}
Obviously if a childLayer.Start < childLayer.Parent.Start => childLayer.Parent.Start = childLayer.Start.
The same kind of logic is used for the Stop attribute as follows: if a childLayer.Stop > childLayer.Parent.Stop => childLayer.Parent.Stop = childLayer.Stop.
Anyway, the fact is that I have already succeeded to create all the objects according to the design above but mainly by using a giant loop running through all the DataRows presents in the Information Table described previously. I also made a version using linq and DataTable as Enumerable() but both versions of my code, are to me, very dirty and hard to maintain. The difficulties are obviously mainly come from the conversion from a Table / DataTable to this set of layer objects
So I'm wondering now how to improve this...
Is there any solution to improve this design?
Any good pattern to use for helping?
Is there any appropriate linqs for filtering and creating dictionaries containing the childlayers with the current Schema of the Information Table.
Thanks.
So why not just
public class ConcreteLayer: Layer
{
public Layer Parent { get; set; }
public Dictionary<Int32, Layer> Children{ get; set; }
}
public class FinalLayer: Layer
{
public Layer Parent { get; set; }
public String ResultTableName { get; set; }
}

Custom model & client validation in MVC without data annotations

I have the below view models, which are used to represent a survey of questions, but they are structured into a more flattened grid to accommodate the default model binder.
// Main ViewModel for the Question View
public class SurveyRowList
{
...
public IList<SurveyRow> SurveyRowList { get; set; }
}
public class SurveyRow
{
public int QuestionId { get; set; }
public int? ParentQuestionId { get; set; }
public int SurveyId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string HelpInformation { get; set; }
public int RenderOrder { get; set; }
public SurveyRowType RowType { get; set; }
// Collection of the same answer control, 1 or more times
// for each line number
public IList<AnswerControl> AnswerControls { get; set; }
}
public enum SurveyRowType
{
QuestionGroup = 1,
Question = 2,
AnswerRow = 3
}
public class AnswerControl
{
public int Id { get; set; }
public int QuestionId { get; set; }
// a reference to the database record answer id
public int SurveyAnswerId { get; set; }
// control type of checkbox, dropdown, input, dropdown-additional-textbox, checkbox-group
public ControlType ControlType { get; set; }
// used to specify getting particular backing data for dropdown and checkbox-group
public ControlSpecificType ControlSpecificType { get; set; }
public string Description { get; set; }
public string HelpInformation { get; set; }
public int RenderOrder { get; set; }
public bool InLine { get; set; }
public int LineNumber { get; set; }
public AnswerControlValueType Value { get; set; }
}
public class AnswerControlValueType
{
// Default string backing value when possible
public string Value { get; set; }
// AnswerCheckBox
public bool CheckValue { get; set; }
// AnswerCheckBoxListModal
public string ModalName { get; set; }
// AnswerMultiSelectListValue
public int[] ListValues { get; set; }
// making the options list setter public so that this data can be re-attached after model binding
public IEnumerable<SelectListItem> ListOptions { get; set; }
// AnswerImageValue
public HttpPostedFileBase Image { get; set; }
// AnswerSelectListAdditionalValue
public string AdditionalInformation { get; set; }
}
Each SurveyRow is like a row of a table. Only the SurveyRowType.AnswerRow actually makes use of the AnswerControls list.
Example of their ordering when rendered by their type and order number can be seen in this image:
The image only shows a few simple examples, and there can be 1-10 lines per page to a max of 100, but I have also added a bit of explanation of some of the validation rules I would want to apply. There are more but these are just a few examples.
My problem is that I want to support this more complex validation but all the rules and error text are stored in a database, 1. because of user configuration, 2. because of existing localisation of the error text to support several languages.
I am looking for any suggestions that people might have to be able to support this.
I have seen things like Fluent Validation and I haven't delved too deep yet but so far I can't see any examples that would specifically not use Data Annotations on a model.. and also RequiredIf or DisabledIf or EnabledIf style validation rules that apply across a slightly more complex collection of objects.
I worked with MVC patterns in 2001 with servlets, and again in 2006, with a custom MVC framework implemented on top of ASP.NET, and looking at what people are doing nowadays makes me believe that most did not even care about looking at what MVC stands for, only that explain the models nonsense. A lot of developers working with ASP.net MVC, tend to bind the data that is coming from the client to models, but that is such a poor design. Models contain the data that should be forwarded to the template manager which is in most cases the Razor engine.
http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
So my advice is: don't link the data that you get from the client into the models.
Get the data from the client, do a search on the Request object if it needs to
Validate the data (fluentvalidation)
apply the business rules
create the models
forward the models to the template engine
Also stopping using those crazy useless annotations.
My question was related to how I can support validating this complex model. I have since looked more at Fluent Validation and that has everything I need to do custom rules for a complex model, i.e. checking values across collections of objects within my model.

Define simple data classes as abstract , interface or just classes?

Rather new to OOP..
I am gonna build a number of small applications that will support our main business.
These apps:
-Will need some common data classes
-The above classes may change in the future as far as properties are concerned (will add properties when ERP versions advance).
For example i have a class:
public class Lot
{
public string SSCC { get; set; }
public InventoryItem Item { get; set; }
public string DescriptionLocalLot { get; set; }
public string DescriptionEnglishLot { get; set; }
public DateTime ProductionDate { get; set; }
public string Shift { get; set; }
public string WorkOrder { get; set; }
public string ProductionLine { get; set; }
public string BarcodeEAN14 { get; set; }
public decimal Boxes { get; set; }
public decimal Units { get; set; }
public decimal Pieces { get; set; }
public DateTime LastUpdated { get; set; }
public string LastUser { get; set; }
public Warehouse LastWarehouse { get; set; }
public string ProductionLot { get; set; }
public string PalletSequence { get; set; }
}
The above class will be used by almost all applications (Windows forms or ASP pages). Ihave put this definition in a separate file called CommonClasses.
Should i define these classes as Abstract or Interfaces better? In most cases these classes will not include methods.
A class should describe all of an object's properties as well as methods that can act upon it. Not all are going to be used at once; but they are provided so that all the behavior is understood and state of an object can be tracked.
The class described in your code seems like a candidate for a concrete class. It provides a set of properties that are stored in memory and act in relation to one object. If you require additional functionality at a later point, you can extend the class to provide this.
If however, each instance of the class requires different implementation; then you should consider abstract class, or perhaps interface.
You should use concrete classes in your case if the change is common for all applications which are using these classes.

How to architect Entity Framework Application (with MEF)

I am desperate to find out how to architect my Entity Framework 4 (code first) application.
I have one VS project that will handle access to my data. Its a MEF-Exported Part [MyData], based on an Interface [IDataExport]. That project has my EF classes (customer, order, etc), the context initializer, etc and all that already works like a dream.
I have one VS project that has my interfaces (all my interfaces). All projects have a reference to this Interface project.
I have one VS project that does all my logging. It is also a MEF-Exported Part [MyLog], based on an interface [ILogging]. That class really just writes to the Console.
I have Three VS projects that we will call Parts (in MEF terms). They are plugins. They need data to work (customers, orders, etc). Actually, they need data as an Input from three different tables, all at once.
I have one project that is the Host application. It is currently running as a console application but will soon be converted to a Windows Service.
I hope that gave you a good idea of the architecture that is in place. Now I am having troubles trying to figure out how to do my data access correctly.
When the host needs data to pass to the plugins, it needs to get data from 3 different tables. Actually, the way it is setup with EF, the three tables will be retrieved at once. How do I pass that data to the plug-in, when the plugin was instantiated by MEF? Can Plug-Ins raise events to interact with the Host application?
In addition, as the plug-ins run, data in the tables will need to be updated. How do I keep my data in the database updated three layers up? The Host can call the Plug-In, but the Plugin doesn't have a way to call the Host. Only the [MyData] project has access to the Database.
Based on the scenario that I described, could someone please tell me how to best architect this application?
Adding further to my confusion, some sample code shows the calling application (in this case the host), starting brand new Models for each search call to the database. e.g.
public List<Customer> FindCustomerList(string companyName)
{
return new CustomerManager().FindCustomerList(companyName);
}
public List<Customer> FindCustomerList(string companyName)
{
var q = from c in context.Customers
where c.CompanyName.StartsWith(companyName)
select c;
return q.ToList();
}
Below are my three tables. Please note that they have foreign key relationships, resulting in sub-items being embedded inside of the main job record. Like a customer with many orders.
public class pcJobAction : IVersionTracking, IpcIdentity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
//IpcIdentity
[Required]
[MaxLength(75)]
public string name { get; set; }
[MaxLength(1000)]
public string description { get; set; }
[Required]
[MaxLength(30)]
public string ServerName { get; set; }
[MaxLength(20)]
public string ServerIP { get; set; }
public int JobEnabled { get; set; }
public virtual ICollection<pcPlugInValue> PlugInText { get; set; }
//JobActions holds a list of Schedules
public virtual ICollection<pcJobSchedule> JobSchedules { get; set; }
//FK to the JobTypes table (Delete Files, Verify Backups, Ping, etc)
public long pcJobTypeId { get; set; }
public virtual pcJobType pcJobType { get; set; }
//IVersionTracking
public DateTime DateCreated { get; set; }
public DateTime LastUpdated { get; set; }
[Timestamp]
public byte[] Version { get; set; }
}
public class pcPlugInValue : IVersionTracking, IpcIdentity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
//IpcIdentity
[Required]
[MaxLength(75)]
public string name { get; set; }
[MaxLength(1000)]
public string description { get; set; }
public string PlugInText { get; set; }
public int ExecuteOrder { get; set; }
//FK to the JobAction table
public long pcJobActionId { get; set; }
public virtual pcJobAction pcJobAction { get; set; }
//FK to the codes table (to indetify the schedule type: daily, weekly, etc)
public long pcCodeId { get; set; }
public virtual pcCode pcCode { get; set; }
//IVersionTracking
public DateTime DateCreated { get; set; }
public DateTime LastUpdated { get; set; }
[Timestamp]
public byte[] Version { get; set; }
}
public class pcJobSchedule : IVersionTracking, IpcIdentity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
//IpcIdentity
[Required]
[MaxLength(75)]
public string name { get; set; }
[MaxLength(1000)]
public string description { get; set; }
//FK to the JobAction table
public long pcJobActionId { get; set; }
public virtual pcJobAction pcJobAction { get; set; }
//FK to the codes table (to indetify the schedule type: daily, weekly, etc)
public long pcCodeId { get; set; }
public virtual pcCode pcCode { get; set; }
public DateTime StartDate { get; set; }
public Boolean dayMonday { get; set; }
public Boolean dayTuesday { get; set; }
public Boolean dayWednesday { get; set; }
public Boolean dayThursday { get; set; }
public Boolean dayFriday { get; set; }
public Boolean daySaturday { get; set; }
public Boolean daySunday { get; set; }
public Boolean ThisJobIsNext { get; set; }
public DateTime EndDate { get; set; }
public int DateOfMonth { get; set; }
public int DayOfWeek { get; set; }
public DateTime ScheduleHour { get; set; }
public int EveryHowMany { get; set; }
public DateTime RunTimeLast { get; set; }
public DateTime RunTimeNext { get; set; }
//IVersionTracking
public DateTime DateCreated { get; set; }
public DateTime LastUpdated { get; set; }
[Timestamp]
public byte[] Version { get; set; }
}
From your architecture description, can I assume that your host application has, somewhere, an [ImportMany] that causes all of your plugins to be instantiated by MEF?
If that is the case, one option is (as I believe you asked) to add an event to your plugin interfaces and attach to that event in each plugin from your host application. I have done that myself and it works fine.
Another option, if it fits into your architecture, is to put your EF classes in a separate assembly, reference that assembly in your plugin assemblies, and do your data access directly from the plugins.
I've done the second option myself, where I have placed my EF code-firstclasses into a seperate assembly, and have some helper classes that are used to connect to the contextclass, and query the ef repository.
However, if you don't want your plugins to have direct access to the entire database, then its probably best to do option 1. Especially if in the future you decided to have your database tables split into different schemas, and you want only certain plugins to be only to interact with specific schema within your database.

Categories

Resources