I have a question...
I have a web service where the OperationContract are retrieve and update.
Using a cars example, I have the retrieve providing an object that contains a list of cars and how many cars. I have that configured through a class.
[OperationContract(Name = "**Retrieve**")]
[FaultContract(typeof(FaultInfo))]
[XmlSerializerFormat]
CarInfo Retrieve(CarRequest CarRetrieve);
[OperationContract(Name = "**Update**")]
[FaultContract(typeof(FaultInfo))]
[XmlSerializerFormat]
CarUpdateInfo Update(CarUPDRequest CarUpdate);
Now the retrieve I do not seem to have a problem with at all. It's looking like it's providing the information; the update, however, is not working.
The CarUPDRequest object is defined with different classes and one of those is a list of cars.
The class is constructed much the same as the CarUpdateInfo and that seems to work.
On the client, I know I can would call the update. But I construct the object CarUPDRequest on the client.
I have the service reference namespace like CarService. I can actually type CarService. (and get the list of class methods like the CarInfo and CarUPDRequest.
A couple of things I noticed is like the .Add for a collection defined by a list. On the client app, I DO NOT get the Add. However, if I try the same thing local on the CarService.cs, it will allow me to do the add:
Example:
CarUpd.Cars.car.add doesn't work on the client but does work on the server. Work as in is an option.
When using something like
var CarUpd = new CarUpdRequest();
Is there something I am missing here?
Any assistance on this would be greatly appreciated.
I solved my issue by doing a List CarUpd = new List();
Related
I'm trying to query a WCF Data Service with oData. Everything works fine, but in a many to many relation the expand Function doesn't work. The Relation is: Product 1-* ProductOrder *-1 Order Here is my code to query the service:
var queryProductOrder = (DataServiceQuery<ProductOrder>)SessionHelper.context.ProductOrder.Expand(x=>x.Product);
var allProductOrders = await queryProductOrder.ExecuteAsync();
If I run this in debug mode and check the allProductOrder Object, there is no Product. The interesting fact is, that when I check the generated OData Query and run it over the browser, the Product gets expanded.
The query looks like this:
http://localhost:10000/ProductOrder()?$expand=Product
And the JSON-Result is expanded:
{"odata.metadata":"http://localhost:10000/$metadata#ProductOrder","value":[{"Product":{"id":1,"Name":"Die Sims","Tax_fk":1,"Price":"44.99","Description":"Lebenssimulation","Stock":"99.00","TotalOrder":"0.00","ProductUnit_fk":1,"Barcode":"121212121","MainImage_fk":null,"Tenant_fk":1,"PurchasePrice":null},"id":1,"Product_fk":1,"Order_fk":1,"Tenant_fk":1,"Amount":"10"}]}
Also confusing is the fact, that on other many to many relations the expand method works like it should.
Why it doesn't expand the allProductOrders Object? Why is the allProductOrders.First().Product object null but the generated OData query returns the Expanded data?
I'm new to WCF data services. I have a quite simple data model. Some of its properties have the same type, like this:
public IQueryable<IntegerSum> HouseholdGoodsSums
{
get
{
return GetData<IntegerSum>(DefaultProgramID, "rHouseholdGoodsPrice", IntegerSumConverter);
}
}
public IQueryable<IntegerSum> StructureSums
{
get
{
return GetData<IntegerSum>(DefaultProgramID, "rStructurePrice", IntegerSumConverter);
}
}
The IntegerSum is a very very simple class:
[DataServiceKey("Amount")]
public class IntegerSum
{
public int Amount { get; set; }
}
When I navigate to my service in a web browser, I see the following error message:
The server encountered an error processing the request. The exception message is 'Property 'HouseholdGoodsSums' and 'StructureSums' are IQueryable of types 'IntegrationServices.PropertyIntegrationServices.IntegerSum' and 'IntegrationServices.PropertyIntegrationServices.IntegerSum' and type 'IntegrationServices.PropertyIntegrationServices.IntegerSum' is an ancestor for type 'IntegrationServices.PropertyIntegrationServices.IntegerSum'. Please make sure that there is only one IQueryable property for each type hierarchy.'.
When I get rid of one of these two properties, the service starts working.
I searched for this error message in google, but haven't found a solution.
Is it really not allowed to have two properties with the same type in a data model? If so, why?
Comrade,
To address the error first, you're running into a limitation in the Reflection provider. Specifically, the Reflection provider doesn't support MEST.
That said, there are better approaches to achieve what you're trying to achieve. You should probably not make IntegerSum an entity type (an entity type is a uniquely identifiable entity, which doesn't really fit your scenario). While you can't expose that directly, you can expose it as a service operation. That seems much closer to what you're trying to achieve.
A couple of ways to distinguish between whether or not something should be an entity:
If it has a key already, such as a PK in a database, it should probably be an entity type
If you need to create/update/delete the object independently, it must be an entity type
HTH,
Mark
I use a Service Operation in WCF data service to get a object.
[WebGet]
public IQueryable<sample> GetSamples(int Id)
I can retrieve data by
http://localhost:xx/GetSamples?Id=9
Is it possible to get property of the returned object similar to
http://localhost:xx/samples(x)/property
I've tried http://localhost:xx/GetSamples?Id=9/property, and http://localhost:xx/GetSamples/property?Id=9 etc. Nothing works.
If Sample is a complex type then this won't work.
If Sample is an entity type, then it will work with a small modification. Property access is only possible on a singleton result. WCF DS doesn't know that your service operation always returns a single entity, to tell is to, add an attribute SingleResult to your service operation method. Then the first URL should work: service/GetSample/PropertyName?id=2
If the Sample is an entity type and you know the key property value (or values) then service/Samples(keypropertyvalue)/PropertyName should also work.
What about using a select?
http://localhost:xx/GetSamples?Id=9&$select=property
Suppose I have a class Customer that is mapped to the database and everything is a-ok.
Now suppose that I want to retrieve - in my application - the column name that NH knows Customer.FirstName maps to.
How would I do this?
You can access the database field name through NHibernate.Cfg.Configuration:
// cfg is NHibernate.Cfg.Configuration
// You will have to provide the complete namespace for Customer
var persistentClass = cfg.GetClassMapping(typeof(Customer));
var property = persistentClass.GetProperty("FirstName");
var columnIterator = property.ColumnIterator;
The ColumnIterator property returns IEnumerable<NHibernate.Mapping.ISelectable>. In almost all cases properties are mapped to a single column so the column name can be found using property.ColumnInterator.ElementAt(0).Text.
I'm not aware that that's doable.
I believe your best bet would be to use .xml files to do the mapping, package them together with the application and read the contents at runtime. I am not aware of an API which allows you to query hibernate annotations (pardon the Java lingo) at runtime, and that's what you would need.
Update:
Judging by Jamie's solution, NHibernate and Hibernate have different APIs, because the Hibernate org.hibernate.Hibernate class provides no way to access a "configuration" property.
One of my applications is a public website, the other is an intranet. The public website runs using a limited security user that must access a certain table through a view, whereas the intranet can access the table itself.
This seems like it would be quite simple to setup using Fluent NHibernate. In my ClassMap I could do a check like this:
public class MyEntityClassMap : ClassMap<MyEntity>
{
public MyEntityClassMap()
{
if (NHibernateConfig.Current.Context == "intranet")
Table("t_MyEntity");
else
Table("v_MyEntity_pub");
... etc
}
}
Is there a simple way of doing this for embedded hbm files? The only method I can think of would be to have two copies of the hbm file, which would be confusing and far from ideal.
Is there perhaps a better way of achieving the same result?
Actually what you ask it is possible. You can actually access the embedded XML files and alter their content before the SessionFactory is build (on Application Start).
Assuming your will choose to reference the "t_MyEntity" in your entities by default here is how you can dynamically change this reference when you want to reference the "v_MyEntity_pub" table instead (the code may not work as it is but you will get the idea):
NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
cfg.AddAssembly(ASSEMBLYNAME);
if (NHibernateConfig.Current.Context != "intranet") //this is how you have stated you distinguish the intranet application from the other one.
{
string[] resourcesNames = assembly.GetManifestResourceNames();
foreach (string resourceName in resourcesNames)
{
StreamReader sr = new StreamReader(assembly.GetManifestResourceStream(resourceName));
string resourceContent = sr.ReadToEnd();
resourceContent = resourceContent.Replace("t_MyEntity", "v_MyEntity_pub");
cfg.AddXmlString(resourceContent);
}
}
ISessionFactory sessionFactory = cfg.BuildSessionFactory();
The above code should be executed only once for the lifetime of your application and only for the intranet application.
Although this is perhaps not the most helpful answer to your problem, I don't believe that this is possible in a mapping file. I also don't think that two hbm files would work for the same name, as it would be unable to distinguish between the two, you would instead have to have two identical objects each with slightly different names and mapping files. Which as you said in your question, would be completely confusing and ideal would simply be a spot on the horizon that you were hoping to, someday, reach.
Why is it that can't access everything directly through the view? I'm assuming there is no writing involved in this process? Is there any way you can change this method of accessing data while still maintaining your security?