I am trying to call a user defined sql function in my linq statement using entity framework. The function is called GetXml, and takes 2 strings called "data" and "path" and returns a string. My Data Model is called XmlDataModel. I included the function definition in the edmx file as so:
<Function Name="GetXml" ReturnType="varchar(max)" Schema="dbo">
<Parameter Name="path" Type="varchar(max)" Mode="In" />
<Parameter Name="data" Type="varchar(max)" Mode="In" />
</Function>
I have the following declaration of the method in my code:
[EdmFunction("XmlDataModel.Store", "GetXml")]
public string GetXml(string path, string data)
{
throw new NotSupportedException("This method can only be used in a LINQ-toEntities query");
}
And the following linq statement:
var test = from e in this.ObjectContext.Events
where GetXml("a", "b") == "test" select e.EventSpecificData;
My problem is that when I attempt to view the result set, I get the following message:
The specified method 'System.String GetXml(System.String,
System.String)' on the type 'RIAServicesLibrary1.Web.XmlDomainService'
cannot be translated into a LINQ to Entities store expression because
the instance over which it is invoked is not the ObjectContext over
which the query in which it is used is evaluated.
It seems to be recognizing that I have the method defined, because when I take out the [EdmFunction] tag I get a different message. Any ideas?
Related
I'm querying a SQL table via an API and I expect the API to return a <IQueryable> collection of 'Outfit' objects however, the response object is actually just a string containing the sql-select statement.
Questions:
Why is the response object returning the SQL-select statement as a string?
Should the IQueryable<> contain a collection of 'Outfit' objecy-types? And should the object-type 'Outfit' be a C# class OR can I use a generic type like 'object' to hold each 'outfit' in the collection?
//Endpoint setup within the APIcontroller.cs file
[Route("api/getSummerOutfits")]
[HttpGet]
[Authorize]
public string getSummerOutfits()
{
IQueryable<Outfit> outfits = _dbContext.Outfits.Where(outfit => outfit.Type == 'Summer');
return outfits;
}
//Setup for the service within the api.service.ts file
getSummerOutfits(): Observable<Object>
{
return this.httpClient.get('/api/getSummerOutfits').pipe();
}
//A snippet of the response-string when the API is called within Postman
"SELECT \r\n ....... WHERE Outfit.Type = 'Summer'"
I have tried setting the IQueryable<> to contain objects of-type 'outfit' however the response continues to be a string containing the sql-select statement.
The query is declared but never executed.
IQueryable<T> (Remarks section)
Enumeration causes the expression tree associated with an IQueryable object to be executed.
Queries that do not return enumerable results are executed when the Execute method is called.
You have to materialize the query with .ToList() or .AsEnumerable().
public List<Outfit> getSummerOutfits()
{
List<Outfit> outfits = _dbContext.Outfits
.Where(outfit => outfit.Type == 'Summer')
.ToList();
return outfits;
}
While I suggest removing.pipe() as you didn't perform any operation in the response. And return the value of Observable<any[]> or Observable<Outfit[]> if you have write Outfit class/interface.
getSummerOutfits(): Observable<any[]>
{
return this.httpClient.get<any[]>('/api/getSummerOutfits');
}
I'm surprised that even worked. Essentially it passed back an IQueryable<Outfit>.ToString() result.
To return a collection of Outfits Yong Shun's answer covers that using a ToList() and having the return type being an IEnumerable<Outfit>/ ICollection<Outfit>.
As a general rule though I don't recommend passing entities back to views or API, especially for asynchronous AJAX calls as this will typically send far more information than the consumer needs, and potentially opens you up to serialization "traps" with lazy loading.
Instead, define a view model or a DTO, which is a serializable POCO C# object containing just the fields your consumer needs. Then your method becomes:
public IEnumerable<OutfitDto> getSummerOutfits()
{
var outfits = _dbContext.Outfits
.Where(outfit => outfit.Type == 'Summer')
.Select(outfit => new OutfitDto
{
// copy values across here.
}).ToList();
return outfits;
}
This avoids the possibility that a serializer attempts to lazy load navigation properties in Outfit. It reduces the size of the payload by just including the fields that you need, and removes any need to eager-load entire related entities if there are details you want from those. (just reference the related entity properties, EF will build the suitable query) It also avoids confusion especially if you go to pass an outfit DTO back to the server rather than attempting to send what you think is an Entity which is actually nothing more than a serialized JSON object or set of parameters type-cast into an Entity class.
I have a problem when using Hibernate Criteria API:
var query = session.QueryOver<MyClass>().Where(param => param.Name == "myFilterName").List<MyClass>();
If a run this statement, a NHibernate.QueryException is thrown:
could not resolve property: Name of: MyClass
And in the StackTrace:
at NHibernate.Persister.Entity.AbstractPropertyMapping.ToType(String
propertyName)
MyClass.hbm.xml file has the property mapped of this way:
<property name="name" access="field">
<column name="NAME" length="50" not-null="true" />
</property>
I think that the problem comes because hibernate can not access the property "Name" of MyClass because is mapped with access="field", but I can not change this way to access the property due application design requirements.
The idea is create querys by using Criteria API with lambda expressions in order to avoid hardcoded string property names.
Also I´ve tried with a Expression with the same exception result:
var criterion = Expression.Where<MyClass>(param => param.Name == "myFilterName");
var result = session.CreateCriteria<MyClass>().Add(criterion).List<MyClass>();
Somebody knows how I can indicate to Criteria API that MyClass has the properties mapped as access="field"?
Help very appreciated.
Not sure of what you want to achieve, having the class code might help.
Anyway, from what you provided, I guess the mapping should be :
<property name="Name" access="field.camelcase">
see http://www.nhforge.org/doc/nh/en/#mapping-declaration-property
Following the technique described here, I was able to populate a domain object that uses custom collections for its children. The relevant property mapping looks like this:
<component name="Contacts" class="My.CustomList`1[[Domain.Object, DomainAssembly]], MyAssembly">
<set name="InnerList">
<key column="PARENT_ID" />
<one-to-many class="Contact" />
</set>
</component>
My custom collection class exposes the InnerList property as an ICollection like so:
protected System.Collections.ICollection InnerList
{
get
{
return this;
}
set
{
Clear();
foreach (DomainObject o in value)
{
Add(o);
}
}
}
This worked like a charm to load data from the database and not have to abandon my rather useful custom collection class.
Then I moved on to try implement saving, and following the advice given in this thread, decided to wrap every call to NHibernate in a transaction.
Now when I commit following my load, NHibernate throws an InvalidCastException: "Unable to cast object of type 'My.CustomList`1[Domain.Object, DomainAssembly]' to type 'Iesi.Collections.ISet'."
Is there a way to make this work the way I expect it to?
EDIT:
Following the lead provided by Raphael, I tried switching to ICollection<T> which gives me a different InvalidCastException when I commit the transaction: Unable to cast object of type 'My.CustomList`1[Domain.Object]' to type 'NHibernate.Collection.IPersistentCollection'.
Change the property to be of type
IList<T>
When I use CF9's ORM feature and generate an explict setter for my ORM CFC, is there anyway to call the default funcitionailty of the ORM CFC after i have done the work needed in the method. For example i am looking for something like this. Obviosuly the code will not run , and super is the wrong concept since the ORM CFC isnt inherting anything, but thats the type of functionality I am looking for.
public void setMovie(String movie){
if(movie == "inception"){
ORMCFC.super().setMovie("Greatest movie ever made")
}else{
ORMCFC.super().setMovie(movie)
}
In your model CFC for the ORM you can specify additional "decorator" functions.
component persistent="true" table="Movie" schema="dbo" output="false"
{
/* properties */
property name="MovieNo" column="MovieNo" type="numeric" ormtype="double" fieldtype="id" ;
property name="Name" column="Name" type="string" ormtype="string" ;
/* decorator */
public void function setMovie(name)
{
if(name == "inception"){
setName("Greatest movie ever made")
}else{
setName(name)
}
}
}
Otherwise if you need to (using your example) setMovie() you will need to do an EntityLoad or create a new entity to set a value to.
For mapping component in nhibernate , is there a way in the hmb file we can indicate a overlaoded constructor to be used instead of default one.
In below mapping nHibernate will use the default constructor of MyClass when reading data from database - I am wondering if we can instruct nhibernate to use a overloaded constructor instead ?
<component name="MyProperty" class="MyClass" >
<property name="Member1" column="member_1" />
<property name="Member2" column="member_2" />
<property name="Member3" column="member_3" />
</component >
Edit #1
Alternatively , does nHibernate allow to map a static value to a property instead of a column ?
Something like below:
<component name="MyProperty" class="MyClass" >
<property name="Member1" column="member_1" />
<property name="Member2" column="member_2" />
<property name="Member3" **value="555"** />
</component >
NHibernate will always use the default constructor to instantiate an object of the type, (unless you want to create some kind of DTO and retrieve it via HQL) and then it will use the properties (or backing fields if specified) to populate the object.
If you have a type for which you do not want to expose a default (no-args) constructor, but you want to make sure that you can only instantiate the type via a specific constructor, then I always do it like this:
public class MyClass
{
private MyClass()
{
// Default constructor has been made private, so it is not usable
// by user code, but NHibernate requires a default constructor
// (it may be private)
}
public MyClass( int member1, int member2, string member3 )
{
}
}
The only standard way you can use constructor with parameters in NHibernate using select new HQL construct:
select new Family(mother, mate, offspr)
from Eg.DomesticCat as mother
join mother.Mate as mate
left join mother.Kittens as offspr
Otherwise it uses parameterless constructors for all purposes. I'm not sure whether this can be altered by hacking NHibernate internals (IClassPersister, IInterceptor, etc.)