Let's say I have a window which should submit 3 model in client side (Silverlight Client Application). My problem is each time I submit the form, data on the server side which I passed them from client are empty.
I've used nested class which contains my models, instead of passing multiple object as parameter, but it didn't work again.
My Personnel Data Transfer Object Code is something like this :
[DataContract]
public class PersonnelDTO : EntityObject
{
[Key]
[DataMember]
public int PersonnelId { get; set; }
[Include]
[DataMember]
[Association("Personnel_ID", "PersonnelId", "Personnel_ID")]
public Personnel Personnel { get; set; }
[Include]
[DataMember]
[Association("Personnel_Info_ID", "PersonnelId", "Personnel_Info_ID")]
public Personnel_Info PersonnelInfo { get; set; }
}
I fill up this model to pass data from client to server (DomainService).
and also my domain service code is :
[Invoke]
public void AddPersonnel(PersonnelDTO personnelDTO)
{
// Model are EMPTY in DTO
ObjectContext.AddToPersonnels(personnelDTO.Personnel);
ObjectContext.AddToPersonnel_Info(personnelDTO.PersonnelInfo);
ObjectContext.SaveChanges();
}
I don't know if there is a way to pass multiple parameter in WCF Service method include Generic List.
Thanks in advance.
First off, you don't want to use Invoke on your service method. You just want an Insert operation. So your method should look like this:
public void InsertPersonnel(PersonnellDTO personnelDTO)
No need for an [Insert] attribute as RIA will automatically generate it by convention of the naming of the method.
The next hurdle you have to deal with is how RIA handles the keys. It uses the keys to determine change-tracking. By DEFAULT - RIA will send down EMPTY objects to the service layer if it thinks the object you are sending down is NOT NEW. It does that to save bandwidth.
You're wrapping your objects in a DTO; RIA doesn't really behave well in that scenario from my experience. What it really expects is a Personnel object with PersonnelInfo object as a child and the PersonnelId as the key. Then you need to setup your associations with IsForeignKey=true so that the keys get updated correctly.
I'll post an example of a complex root aggregate object that I use in a sample application that I'm going to blog about shortly (we're using RIA with POCO and Oracle and it works; but it took some figuring out).
[MetadataType(typeof (TicketMetadata))]
public partial class Ticket
{
internal sealed class TicketMetadata
{
[Key] public int TicketId;
[Required]
public DateTime IncidentDate;
[Required(ErrorMessage = "Missing Customer")]
public int CustomerId;
[Required(ErrorMessage = "Missing Product")]
public int ProductId;
[Include]
[Association("Ticket_Customer", "CustomerId", "CustomerId", IsForeignKey = true)]
public Customer Customer;
[Include]
[Association("Ticket_Product", "ProductId", "ProductId", IsForeignKey = true)]
public Product Product;
[Include]
[Composition]
[Association("Ticket_TicketActions", "TicketId", "TicketId")]
public List<TicketAction> TicketActions;
}
}
I'd recommend looking at the way Association and foreign keys work and rethinking your object structure and possibly moving away from the DTO. Done right, the whole thing works pretty well.
Related
The following class was Auto generated from a template using the Entity Framework Model.
namespace Entities
{
using System;
using System.Collections.Generic;
public partial class Country
{
public Country()
{
this.Regions = new HashSet<Region>();
}
public long CountryId { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public bool Preferred { get; set; }
public System.DateTime LastChanged { get; set; }
public virtual ICollection<Region> Regions { get; set; }
}
}
I have a Wcf web service that returns POX (Xml) and Json only. I am wanting to return my own serialised object like;
public class MyResponseObject
{
public int RequestId {get;set;}
public List<Country> CountryList {get;set;}
//other properties
}
But I don't want to return the Regions ICollection.
The object can then be returned using something like
Newtonsoft.Json.JsonConvert.SerializeObject()
Am I best returning my own serialised POCO object in this manner ?
In projects like these, your classes can be split into two types:
Database entity objects (what Entity Framework works with)
Data contract objects (what WCF or your web-service works with)
While it is possible to use the same objects for both, it is not recommended because the database entity objects are an internal implementation concern that is separate from the external interface (your webservice). You might add or remove columns to your database table and not want your API contracts to change. But usually you'll want to hide information from service-consumers, like a database table Users ( UserId, Password ), you definitely don't want the Password property going out!
Another reason not to is that you later might want to add attributes to your webservice contract classes (e.g. to control output formatting or input validation), adding these to entity objects is painful, if not impossible in some cases.
I know it sounds like a needless duplication of work as the majority of classes will have identical members, but it makes sense from a long-term perspective.
Fortunately tools like AutoMapper can speed-up the process of copying data from your database entity objects to your data contract objects.
I'm building an app using code first and generating the DB.
I can no longer modify the DB so, I can't add/change columns and tables. But the Domain Model (not sure if I'm using the term correctly) requires new properties (that are part of the domain) that can be inferred from the database data, but do not exist explicitly.
My database stores sales info for houses. So I have two tables, Houses and Sales. The tables are related by houseID. Now I want houses to have a property called LastSaleDate, but I can't change the underlying database.
So, How would I properly construct this new property and add it into the appropriate layer? Here is what my poco/entities look like. Just pseudo coded...
[I am trying to learn all I can about the tools and methods I use. I may be completely wrong on all my assumptions and maybe I am to add it to my pocos. If that is the case please explain how that would work]
[Table("HOUSE_TABLE")]
public class house {
//some properties
public int HouseID {get;set;}
}
[Table("SALE_TABLE")
public class sale {
//some properties
public int HouseID {get;set;
public int SaleID {get;set;}
public datetime SaleDate {get;set;}
public virtual House House {get;set;}
}
I almost feel like this would create 2 levels of mapping. Though, I don't believe I've ever seen this done in any code I've seen online.
poco -> AutoMapper?? -> entities -> Automapper -> viewModels
This logic most likely belongs on the Entity. Entities should have both data and behaviour. What you seem to be describing is some behaviour that is exposed as a property. So, you should add a property for the derived value to your entity. By default, if the property only has a getter, then EF will not try to map the value to the database.
For example:
[Table("HOUSE_TABLE")]
public class house
{
//some properties
public int HouseID {get;set;}
public virtual ICollection<Sale> Sales { get; set; }
public DateTime LastSaleDate
{
get
{
return this.Sales.OrderByDescending(s => s.SaleDate).First();
}
}
}
In my app, I've been using a DB that stored its IDs as strings. The DB also stored another property (Etag) for each document/row. Because of that, I've had my domain entities derive from this base class:
public class EntityBase : NotifyPropertyChangedBase
{
public string Id { get; set; }
public Guid ETag { get; set; }
}
Now I'm adding another data layer to my application, and I don't want to remove the old one. It would be nice to be able to switch and use a particular data layer based on a run-time decision. The issue is that I want to store Id as an int in the new DB. And ETag is an unnecessary concept in that new DB.
I'm struggling with how to manage this change. If I change EntityBase.Id to an int, then the old data layer won't compile. I'd like to use a certain EntityBase if using the old data layer, and a different EntityBase if I'm using the new data layer. That's just one thought. Maybe there's a better approach? Any suggestions on how I can make this work?
By the way, I believe that persistence layer issues shouldn't work there way up into domain layer objects (like Id being a string or int). However, it's too late, and this is the situation in which I find myself. I'm hoping someone has some good advice on how to proceed.
I was thinking about adding an Id2 to EntityBase:
public class EntityBase : NotifyPropertyChangedBase
{
public string Id { get; set; }
public int Id2 { get; set; } // New property for new DB only
public Guid ETag { get; set; }
}
Then, in my new DAL mapping, I would map the Id column in the table to Id2 instead of Id. But that's not going to work because my business logic references Id only. Still thinking... I may be stuck...
As a hack, I could leave EntityBase in its original form. Then, in the new DAL, when I perform the ORM, I could just convert the ID of the table to a string.
I suggest to add one more layer then.
For instance, to create a new class like this:
public abstract class CommonEntityBase<T> : NotifyPropertyChangedBase{
public T Id {get;set;}
}
And then, derive your old EntityBase from this class:
public class EntityBase : CommonEntityBase<string>{
//this property is present only in this old implementation
public Guid ETag { get; set; }
}
So now, you can create a new layer and use a base class for that as well:
public class FancyEntityBase : CommonEntityBase<int>{
//No ETag concept here - ad new properties, methods, etc.
}
However, there is a question if you really need to change your primary keys to be integers.
This may result in performance issues when the ORM is used.
Need a little help please if anyone can shed some light on this.
I've created a code-first MVC 3 application which I have working fine. I'm refactoring now to remove as much coupling as possible as I want the domain model to be used in various other MVC 3 applications later on. What I have now is a collection of entities which are persisted via a normalised database and they are CRUD-ed through a repository pattern. I have used Ninject to DI the repositories via the controller's constructor and am using models within the MVC 3 project to act as DAOs.
So, within the domain I have an entity called Case that has a foreign key to another case Client that looks like this:
public class Case : ICase
{
[Key]
public int CaseId { get; set; }
public string CaseName { get; set; }
public DateTime DateCreated { get; set; }
public IClient Client { get; set; }
}
Then I have an interface (the interface exists mainly to implement it to the view model to add my data annotations - I know I could add the annotations to the domain object but as I said I want to use this domain model in other applications which will have a different ubiquitious language.
public interface ICase
{
int CaseId { get; set; }
string CaseName { get; set; }
DateTime DateCreated { get; set; }
IClient Client { get; set; }
}
And then I have my view model within the MVC 3 project.
public class CaseModel : ICase
{
[HiddenInput(DisplayValue = false)]
int CaseId { get; set; }
[Required(AllowEmptyStrings = false)]
[MaxLength(100)]
string CaseName { get; set; }
[RegularExpression("")]
DateTime DateCreated { get; set; }
IClient Client { get; set; }
}
So, my first problem is this: changing my foreign key reference for Client to IClient is a new thing, and it returns a null object. When the type was a concrete class it returned fine - I assume this is because EF4.1 tries to create an instance of IClient. Am I totally wrong here or is there a way around this?
My second problem (which may negate my first problem) is am I also doing something wrong by adding data annotations to a view model inheriting the interface of my domain entity? Should I be using model meta data? If so, how do I use meta data in such a way that I can make the data annotations unique to each project without touching the domain?
Thanks!
Caveat: I'm not an expert on EF or MVC3.
We're in the process of building EF Code First entities, and we're not planning on adding interfaces to the entities. Repositories get interfaces. Units of Work get interfaces. Entities don't. Repositories return concrete entities, which are POCOs. Entities may be coupled to related entities. Models and other classes will typically get repository interfaces and/or unit of work interfaces injected in. For testing, we'll just new up some POCO entities and return them from the mock repositories.
We're planning to make the relevant POCO properties virtual so that EF can create proxies.
If you want to decouple a view from concrete entities, I'd first ask what value you expect to gain from that. Is the view going to be reused with different entities? If so, one option would be to use something like AutoMapper to copy the properties over. You'd have to be aware of the immediate access of lazy-load properties, though.
I am using RIA Service in our Silverlight application. Database entities are not directly exposed to a client but I have a set of POCO classes for it. Then in CRUD methods for these POCO classes they are converted to database entities and saved to database.
The problem arises on the server side when client creates 2 new POCO entities which are related. Insert method is called on the server for each POCO entity separately and I may create corresponding new database entities there and add them to object context. But I see no way to add relation between these created database entities. Is there a solution for that?
For example, I have these 2 POCO entities (simplified):
[DataContract(IsReference = true)]
public partial class Process
{
[DataMember]
[Key]
public string Name
{
get; set;
}
[DataMember]
public long StepId
{
get; set;
}
[DataMember]
[Association("StepProcess", "StepId", "Id", IsForeignKey=true)]
public Step Step
{
get; set;
}
}
[DataContract(IsReference = true)]
public partial class Step
{
[DataMember]
[Key]
public long Id
{
get; set;
}
[DataMember]
public string Name
{
get; set;
}
}
And I have these 2 Insert methods in my domain service class:
public void InsertProcess(Process process)
{
var dbProcess = new DBProcess();
dbProcess.Name = process.Name;
//dbProcess.StepId = process.StepId; Cannot do that!
this.ObjectContext.AddToDBProcess(dbProcess);
}
public void InsertStep(Step step)
{
var dbStep = new DBStep();
dbStep.Name = step.Name;
this.ObjectContext.AddToDBSteps(dbStep);
this.ChangeSet.Associate<Step, DBStep>
(step, dbStep, (dto, entity) =>
{
dto.Id = entity.Id;
});
}
Client adds a new Process, then creates and adds a new Step to it and then calls SubmitChanges(). Process.StepId is not filled with a correct value as there is no correct Step.Id for the newly created step yet, so I cannot just copy this value to database entity.
So the question is how to recreate relations between newly created database entities the same as they are in newly created DTOs?
I know about Composition attribute but it is not suitable for us. Both Process and Step are independent entities (i.e. steps may exist without a process).
There are two ways to solve this:
Have each call return the primary key for the item after it is created, then you can store the resulting PKey in the other POCO to call the second service.
Create a Service method that takes both POCOs as parameters and does the work of relating them for you.
Thanks, although both these suggestions are valid but they are also applicable only for simple and small object hierarchies, not my case. I end up using approach similar to this. I.e. I have a POCO to database objects map. If both Process and Step are new, in InsertProcess method process.Step navigation property is filled with this new step (otherwise StepId can be used as it referenced to existing step). So if this process.Step is in the map I just fill corresponding navigation property in DBProcess, otherwise I create new instance of DBStep, put it to the map and then set it to DBProcess.Step navigation property. This new empty DBStep will be filled in InsertStep method later.