Suppose I have 2 tables:
Person(personid, ...)
PersonPhone(ppid, persond, phoneid, ...)
in meta data define PersonPhone as composite:
[Include]
[Composition]
public EntityCollection<PersonPhone> PersonPhonees { get; set; }
then I try to reload Person data for refresh functionality. What I did is to detach Person before call wcf ria service to load Person Data again in view model:
Context.Persons.Detach(this.Person);
it works fine for all data loaded from table Person. then I test it for PersonPhone:
Suppose personid=1, there are 3 phones for this person:PhoneID: 1,2,3
then in code, I removed one row from PersonPhone:
this.Person.PersonPhonees.Remove(Phone(1));
for testing, I did not submit the change, then I reload the Person data. Person data is reloaded from DB but PersonPhone still only have 2 rows: phone(2), Phone(3), but it should have 3 rows for all phone: 1,2 and 3.
How to resolve this problem?
You will have to manage the refresh on your own. WCF RIA doesn't replace (or remove) any data that you have cached in the Silverlight client.
In your case, you called Remove(...). WCF RIA respects that modification to the data. When you load Person again, WCF RIA should not add Phone(1) as you have removed it.
Perhaps you want to call RevertChanges() before the load on the entire context:
_domainContext.RejectChanges();
Or just the Person entities:
_domainContext.EntityContainer.GetEntitySet<Person>().RejectChanges();
That will undo the Remove(Phone(1)) change and allow the query to re-add the phone to the context.
Related
Let's say I have database with two tables - Groups and Items.
Table Groups has only two columns: Id and Name.
Table Items has three columns: Id, GroupId and Name.
As you can see, there is one-to-many relation between Groups and Items.
I'm trying to build a web service using WCF and LINQ. I've added new LINQ to SQL classes file, and I've imported these two tables. Visual Studio has automatically generated proper classes for me.
After that, I've create simple client for the service, just to check if everything is working. After I call GetAllGroups() method, I get all groups from Groups table. But their property Items is always null.
So my question is - is there a way to force WCF to return whole class (whole Group class and all Items that belong to it)? Or is this the way it should behave?
EDIT: This is function inside WCF Service that returns all Groups:
public List<Group> GetAllGroups()
{
List<Group> groups = (from r in db.Groups select r).ToList();
return groups;
}
I've checked while debugging and every Group object inside GetAllGroups() function has it's items, but after client receives them - every Items property is set to null.
Most likely, you're experiencing the default "lazy-loading" behavior of Linq-to-SQL. When you debug and look at the .Items collection - that causes the items to be loaded. This doesn't happen however when your service code runs normally.
You can however enforce "eager-loading" of those items - try something like this:
(see Using DataLoadOptions to Control Deferred Loading or LINQ to SQL, Lazy Loading and Prefetching for more details)
public List<Group> GetAllGroups()
{
// this line should really be where you *instantiate* your "db" context!
db.DeferredLoadingEnabled = false;
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Group>(g => g.Items);
db.LoadOptions = dlo;
List<Group> groups = (from r in db.Groups select r).ToList();
return groups;
}
Do you get the Items collection populated now, when you call your service?
I'm exploring Domain Driven Design for the first time and stuck with some questions in mind which I would like to discuss. One of them is...
I'm designing a web application for order maintenance. When the user creates a new Order, the system opens up a new order entry screen. It will generates an Application Number and some pre-configured information pertaining to order restrictions (from database) which the user has to select specific to this order being created.
Now the question I have in mind ....
1. How to go about generating this NEW order entry screen with Application Number generated and some information pulled in from database from DDD stand point?
2. Do I have to use an OrderFactory to create a NEW Order (with App# and restrictions populated) and then translate it to DTO and send it across to Presentation Layer?
3. After filling in the necessary details, when user submits the Order, what should be the process to follow to persist it? say presentation layer sends in a OrderDTO to service layer and then service layer should do what?
The following is a very small sample which can give you a little idea about the lifecycle.
Note that this is sort of traditional DDD style, you may want to separate the read model from the write model (CQRS) and make the UI task based.
In Presentation code (Controller)
var newOrder = _orderService.NewOrder(); // return a new DTO containing the generated id.
// Fill the updated info.
_orderService.SubmitOrder(updatedOrder);
In Service Layer (Application Layer)
public OrderDTO NewOrder()
{
var newOrder = OrderFactory.CreateNew(); // Create a new order which generate an id
return _mapper.Convert<OrderDTO>(newOrder); // Construct OrderDTO for the new order
}
public void SubmitOrder(OrderDTO orderDTO)
{
var order = _mapper.Convert<Order>(orderDTO); // Construct order entity from DTO
order.Activate() // Call some business logic in the domain
_orderRepository.Save(order); // Save order in repository
}
DDD is all about capturing the user intention .So put more questions like
1) Why did the user want to create order -- Command
2)what should happen after the user has created the order. what is that mean to the domain model -- Events coming out of domain
please look at CQRS pattern for more info
In my SL Application I have multiple DomainService Classes which deals with the specific entities. Now I need to call upon a method from DomainService Class 1 in Class 2. How do I do that?
e.g
Product entity is handled in Class2 whereas the Workflow entities are handled by Class 1.
I have created a custom class which has properties from entities. Now I need to access the WorkflowStatus fields from one of Workflow entities for the relevant product in Class 2.
How can I call the Class1 method (GetLatestStatus(int productID)) from Class2's method GetProudctwithStatus()
public IList<ProductVS> GetProductsWithStatus()
{
var result = (from p in this.ObjectContext.Products
select new ProductVS
{
ProductID = p.ProductID,
Code = p.Code,
// ???
WFStatus = **Class1.GetLatestStatus(p.ProductID)**
}).ToList();
return result;
}
Any response would be much appreciated
If this is a common task I would instead create an operation on the Server which returned the data that you need. You can do this by creating the method and utilizing the [Invoke] attribute.
Otherwise you need to call two methods, both of which are asynchronous. If this was my project I would make the first call, then send a list of ProductID's to the server to retrieve the WorkFlow status. Otherwise you would be making N number of service calls to the server (one per each entity returned from the server) which is bad.
I want to load some data with a SP.
I've put a SP in a Linq to SQL Class and I don't know how to use it for loading it's data in a datagrid.
In LinqToSqlDomainService I can't figure out how to call a SP.
What steps should I use.
Any samples of this ? All samples use a table.
Thank's
This post should hopefully be of help:
http://blogs.msdn.com/brada/archive/2009/08/24/business-apps-example-for-silverlight-3-rtm-and-net-ria-services-july-update-part-24-stored-procedures.aspx
You can create empty view with the same structure of your sproc and map that stored procedure to your function in your DomainService
See sample on http://cid-289eaf995528b9fd.skydrive.live.com/self.aspx/Public/sproc.zip
I found the following excellent step-by-step guide at this site -
http://betaforums.silverlight.net/forums/p/218383/521023.aspx
1) Add a ADO Entity Data Model to your Web project; Select generate from database option; Select your Database instance to connect to.
2) Choose your DB object to import to the Model. You can expand Table node to select any table you want to import to the Model. Expand Stored Procedure node to select your Stored Precedure as well. Click Finish to finish the import.
3) Right click the DB model designer to select Add/Function Import. Give the function a name (same name as your SP would be fine) and select the Stored Procedure you want to map. If your SP returns only one field, you can map the return result to a collection of scalars. If your SP returns more than one field, you could either map the return result to a collection or Entity (if all the field are from a single table) or a collection of Complex types.
If you want to use Complex type, you can click Get Column button to get all the columns for your SP. Then click Create new Complex type button to create this Complex type.
4) Add a Domain Service class to the Web project. Select the DataModel you just created as the DataContext of this Service. Select all the entitis you want expose to the client. The service functions should be generated for those entities.
5) You may not see the Complex type in the Entity list. You have to manully add a query function for your SP in your Service:
Say your SP is called SP1, the Complex type you generated is called SP1_Result.
Add the following code in your Domain Service class:
public IQueryable<SP1_Result> SP1()
{
return this.ObjectContext.SP1().AsQueryable();
}
Now you can compile your project. You might get an error like this: "SP1_Result does not have a Key" (if you not on RIA service SP1 beta). If you do, you need to do the following in the service metadata file:
Added a SP1_Result metadata class and tagged the Key field:
[MetadataTypeAttribute(typeof(SP1_Result.SP1_ResultMetadata))]
public partial class SP1_Result
{
internal sealed class SP1_ResultMetadata
{
[Key]
public int MyId; // Change MyId to the ID field of your SP_Result
}
}
6) Compile your solution. Now you have SP1_Result exposed to the client. Check the generated file, you should see SP1_Result is generated as an Entity class. Now you can access DomainContext.SP1Query and DomainContext.SP1_Results in your Silverlight code. You can treat it as you do with any other Entity(the entity mapped to a table) class.
Calling a stored procedure is trivial. Import it as a function and then invoke the function as a member of the DDS. The return value is an ObservableCollection<> that you can use to set up the DataContext of the object you want to bind.
...unless you want to use it in a Silverlight RIA app via the magic code generated proxy, in which case your goose is cooked unless your result rows exactly match one of the entities. If you can meet that criterion, edit the DomainService class and surface a method that wraps the ObjectContext method.
i think my whole questions is inside title bar =]
but i'll explain little more.
i've got 2 related tables in database ( Customers and Orders )
and wcf service which returns Customer and all related Orders as DTO's
like this :
class CustomerDto
{
int ID;
IList< OrderDto > Orders;
}
and :
class OrderDto
{
int ID;
string someString;
}
what is happening:
client asks for customer (customer is returned with orders ), makes some changes (adds/removes orders, changes someString), and sent data back to service.
here i wanted to ask, is it possible to attach modified Customer to database context,
or i'll need make changes manually?
Thank You !
Here's an article with downloadable code sample on using EF and WCF together, including updates. You can also look at RIA services.