I need to edit data in a WCF RIA Domain Service. all examples I can find are using a datagrid.
I have the following but it is retuning a null value, where am I going wrong???
var mytask = from v in DomainRentDetail.tblRentDetails
where v.CustID == xCustID
select v;
tblRentDetail t = mytask.FirstOrDefault<tblRentDetail>();
t.ReturnDate = DateTime.Now;
DomainRentDetail.SubmitChanges();
Please give us more detail but,
I think it must be like this, In a domain service class (I suppose you are on web project)
from v in this.ObjectContext.tblRentDetails
where v.....
select v
If there are some records on your table tblRentDetails
you may check it by FirstOrDefault << Type >> ()== null
When you create your domain service class you must choose your domain(edmx). Then ObjectContext carries your entitiy objects. Ask your Entities to this ObjectContext member.
Note: The below state is an extreme stuation. Maybe you may face off laterly.
If you need diffrent model you are not created domain service class for
there are some other technics,
//Scope level domain service class definition. Not offered.
//Generally views solves this issue
using(XDomainService service=new XDomainService())
{
from one in service
from two in this.objectContext
where...
select new member
}
Related
My app links invoices, contracts and services with Many-to-One-Relationships:
class Invoice(models.Model):
contract = models.ForeignKey(Contract, on_delete=models.CASCADE)
class Contract(models.Model):
service = models.ForeignKey(Service, on_delete=models.CASCADE)
Whenever a new invoice is registered, it can be linked to a service and split/billed internally. Unfortunately, some contracts/invoices need to be linked to more than one service according to a fixed split (e.g. 30/70).
For this to work on the surface, I could to reverse the relationship between contracts and services –
class Service(models.Model):
contract = models.ForeignKey(Contract, on_delete=models.CASCADE)
– or change the ForeignKey field on the Contract class to a ManyToManyField.
But in both cases, I will not be able to get back from the invoice to the service easily anymore, as with the following statement:
invoices = Invoice.objects.filter(models.Q(contract__service__building=self.tenant.unit.building), models.Q(begin__lte=self.begin, end__gt=self.begin) | models.Q(begin__gt=self.begin, begin__lt=self.end))
Is it wise to insert an intermediate helper model (ContractService) with two ForeignKey fields to keep the current app logic and add the option to link a contract to more than one service?
Ok just to clarify one example:
Contract is "Cleaning of House"
Services are "Cleaning of first floor" and "Cleaning of second floor"
Invoices are "Invoice1", "Invoice2", ...
You want a relationship that "Invoice1" can be linked to "Cleaning of first floor" AND "Cleaning of second floor".
models.py
class Contract(models.Model):
"""Can hold multiple Services"""
pass
class Service(models.Model):
"""Is linked to one specific Contract"""
contract = models.ForeignKey(Contract, on_delete=models.CASCADE)
class Invoice(models.Model):
"""Can hold multiple Services and one Service can hold multiple Invoices"""
service = models.ManyToManyField(Service)
Now your question is:
"I can easily get the contract when I have the Service object, but how can I get the Service when I have the Contract object?
con = Contract.objects.all().first()
queryset = con.service_set.all() # gives you all related Services for that specific Contract
Read more about ManytoOne
And:
"How can I get the Invoice when I have the Service object?"
ser = Service.objects.all().first()
queryset = ser.invoice_set.all() # gives you all related Invoices for that specific Service
Read more about ManyToMany
Let me know how it goes
Thanks to #Tarquinius for your help – I found a solution based on his suggestion. The three models in question are connected as follows:
class Service(models.Model):
pass
class Contract(models.Model):
services = models.ManyToManyField(Service)
class Invoice(models.Model):
contract = models.ForeignKey(Contract, on_delete=models.CASCADE)
The query quoted above did not even need to be modified (apart from the different fieldname) to reflect the possibility of more than one service per contract, I just had to add the distinct() function:
invoices = Invoice.objects.filter(models.Q(contract__services__building=self.tenancy_agreement.unit.building), models.Q(begin__lte=self.begin, end__gt=self.begin) | models.Q(begin__gt=self.begin, begin__lt=self.end)).distinct()
In hindsight, this is quite obvious (and simple).
I have a Silverlight 4 application with EntityFramework as data layer.
There are two entities: Customer and Products. When I get customer from a database, the related products are also read, as I added related 'Include' attribute in customer's metadata and call Include method in get query:
public IQueryable<customer> GetCustomerSetById(int customerId)
{
return this.ObjectContext.CustomerSet
.Include(o => o.Products)
.Where(o => o.Id = customerId);
}
The problem that when I change any property in customer's product I get this exception:
This EntitySet of Type
'MyApp.Web.Models.Product' does not
support the 'Edit' operation.
But everything works if I read customer products directly, e.g. not through customer entity (CustomerContext) , but via product one (ProductContext).
Also there is the IsReadOnly=true property in a product entity.
UPDATE:
I have all CUD operations and also marked all of them with related Insert, Update and Delete attributes. Otherwise it wouldn't work at all, but it works for me in some cases as I wrote above.
Any ideas?
This is the real problem with RIA+EF so we keep all our entities in one domain service because at client side it is difficult to deal with multiple entities related via navigation properties. Think for a minute it actually makes no difference and we use EF T4 template to generate all domain service operation in one class. And we generated partial methods to intercept logic of domain service methods.
It sounds like you need to make sure you have an update operation in your domain service. It will look something like this:
public void UpdateProduct(Product product)
{
ObjectContext.Products.AttachAsModified(product, ChangeSet.GetOriginal(product));
}
RIA Services EntitySet does not support 'Edit' operation
Since the aforementioned solutions do not appear to be helping try using this:
Domain Service Wizard
This wizard should look at your entity, and generate the appropriate CRUD operations.
If you then cant update your entities you have a different problem.
Have you tried moving the Include to the end?
Return this.ObjectContext.CustomerSet
.Include(o => o.Products)
.Where(o => o.Id = customerId);
Could be:
Return (from o in this.ObjectContext.CustomerSet
where o.Id = customerId
select o).Include("Products");
Let's say I have Category > SubCategory > SubSubCategory > Item set up in my EF entities.
What is the best way to get Category, Subcategory, SubSubCategory and Item where Item.Property = x all in one single request to the server using WCF RIA Services?
With .Include I can only get the children of the entity, not grandchildren and further down ( or up depending on how you look at it).
Furthermore, if I do this...
public IQueryable<ToolingTreeItem> GetTree(int currentLocationId)
{
var tree = from tc in this.ObjectContext.ToolingCategories
from tg in tc.ToolingGroups
from tt in tg.ToolingTypes
from t in tt.Toolings
where t.CurrentLocationId == currentLocationId
select new ToolingTreeItem { Cat = tc, Group = tg, Type = tt, Tool = t };
return tree;
}
...the method is not available on my context in the client side project, presumably because my custom entity class ToolingTreeItem is not recognized somewhere in the mysteries of the deep chasm that is WCF RIA Services.
If it isn't obvious by now, all I want to do is populate my TreeView with Category > SubCategory > SubSubCategory > Item in a single call to the server. What is the best approach?
Many happy returns!
You should be able to load the entities by using eager loading.
Assuming that you add "[Include]" to the "parent" attributes in you metadata something similar to the code below should work (note that I have guessed the name of all relations so you will probably need to edit the code)
public IQueryable<Toolings> GetToolsWithTree(int currentLocationId)
{
var tree = from t in this.ObjectContext.Tooling.Include("ToolingType.ToolingGroup.ToolingCategory")
where t.CurrentLocationId == currentLocationId
select t;
return tree;
}
It looks like ToolingTreeItem is a complex object, rather than an entity. Unfortunately, RIA services can't generate classes on the client side that are a mix of complex objects and entities - the class has to be entirely one or the other. The two solutions that I'm aware of are to make the ToolingTreeItem an 'entity', by putting the Key attribute on a property, or just make several requests for the data. I've also found this a real limitation.
I constructed my Entity Model. One of my business objects,let's call it Store has a spatial data type. Very quickly I figured out that spatial fields aren't mapped via EF4. However I struggled my way out, by editing the xml declarations defining a query like the following:
<EntitySet Name="Stores" EntityType="Eltrun.OnShelfAuditModel.Store.Stores">
<DefiningQuery>
SELECT [rowId], [storeName], [location].STAsText() as location FROM Stores
</DefiningQuery>
</EntitySet>
At this point I decided to customize my Store entity via a partial class like this, just to make the conversion and still keep the SQLGeography data stored, returning just a double[] at client (as I cannot return neither SqlGeography, neither Location (Bing datatype).
public partial class Store
{
public double[] StoreLocation
{
get
{
SqlGeography geoLocation = SqlGeography.
STPointFromText(new SqlChars(this.location.ToCharArray()), 4326);
return new double[]{
(double)geoLocation.Lat,
(double)geoLocation.Long};
}
}
}
How can I make aware the Store data type of my little customization, at client project?
Thank you!
Just add a setter to your property, and the RIA Services code generator and serializer should create the equivalent property on the client's version of the Store class.
Hope that helps...
I have a problem with Linq and ObservableCollections in my WPF application.
Context of the problem:
I've created a very simple SQL database with two tables: User and BankAccounts.
The User Table has an one-to-many relationship with the BankAccounts Table. Next I've created Linq-to-SQL dataclasses, which worked fine ==> the assosiation between the two tables was detected as well.
Next I've created a function to retreive all Users which works fine:
DataClassesDataContext dc = new DataClassesDataContext
var query = from u in dc.Users
select u;
Now suppose I want to add a new BankAccount to each user (not very likely but still).
I could add the following code
for each(User u in query)
{
u.BankAccounts.Add(New BankAccount());
}
The above works all fine. The BankAccounts property is automaticly part of the User class, due to the assosiation in the database and Linq DataClasses.
However, in my application I first add the query results to an ObservableCollection. Hereby I could use all sorts off databinding and changenotification. This is accomplished by the following code;
ObservableCollection<User> oUsers = new ObservableCollection<User>(query);
Problem: Within the ObservableCollection I can't do anyting with the users BankAccounts property because it is now of type EntitySet<>. So I can't do the following statement anymore.
for each(User u in oUsers)
{
u.BankAccounts.Add(New BankAccount());
}
Somehow, when queryresults are added to an observablecollection It is not possible to acces the user.BankAccounts properties anymore. However, it is possible to bind the BankAccounts Property to any control, like a listbox, and it contains the correct data.
Does someone now how I can create an observableCollction (or similar collection) from wich I can access these "assosiated" properties? I'm realy looking forward for to a solution.
Thanks in advance!
Best regards,
Bas Zweeris
E: Bas.Zweeris#Capgemini.com
Keep track of the original query which will implement IQueryable, you can run any further queries you need against that.
The ObservableCollection should just be for WPF to have something to bind to - its very useful if you want to add a new collection item but not have it pushed to the database before the user has had chance to edit it.
eg.
// Create a new blank client type
var ct = new ClientType()
{
IsArchived = false,
Description = "<new client type>",
Code = "CT000",
CanLoginOnline = true
};
// Tell the data source to keep track of this object
db.ClientTypes.InsertOnSubmit(ct);
// Also add the object to the observable collection so that it can immediately be shown in the UI and editted without hitting the db
clienttypes.Add(ct);