Return an Object from Database.SqlQuery - linq

There's a way with Database.SqlQuery to return the new object created ?
With Linq I do it this way :
Category category
db.Categories.Add(category);
db.SaveChanges();
return category;
Now category is an object that return the new category created with the new id.
How to do it with SqlQuery?
return db.Database.SqlQuery<Category>("INSERT INTO " + categoryTable + " (title,description) VALUES ({0},{1}) ", category.title, category.description);
It returns a empty array but i want to return the new category created with the new id.
Thank you.

I'm guessing you need this because Category has an autonumber Id property of some kind. Haven't tested this myself, but maybe you can get that to work by using the output clause of the insert statement. e.g.
return db.Database.SqlQuery<Category>("INSERT INTO " + categoryTable + " (title,description) OUTPUT inserted.id, inserted.title, inserted.description VALUES ({0},{1}) ", category.title, category.description);

Related

hibernate - Dynamic sort in a query

I have a Dao method that returns list of "posts" and looks like this:
public List<PostDTO> getPosts() {
Session session = sessionFactory.getCurrentSession();
return postList = session
.createQuery("select new com.poster.app.dto.PostDTO(p.id, p.date, p.title, p.text, p.imageUrl, p.author, p.category, count(c.post.id)) "
+ "from Post as p left join Comment as c ON p.id = c.post.id group by p.id",
PostDTO.class).getResultList();
}
So it basically just creates query and returns the dto's in that case. The thing is, i need to fetch exact same list BUT with different sorting. like i need to sort it dynamically by "newest", "most popular" and by "comments number" and i want to do this in one method instead of creating 3 methods for each ("newest", "most popular" and by "comments number"), how can i do that in hibernate?
You have choice between :
Use api criteria to build your query and add dynamically your order by clause.
Add the order by clause at the end of your query depending on your param
ex with 2nd option:
public List<PostDTO> getPostsOrderBy(String orderParam)
{
Session session = sessionFactory.getCurrentSession();
String query = "select new com.poster.app.dto.PostDTO(p.id, p.date, p.title, p.text, p.imageUrl, p.author, p.category, count(c.post.id)) "
+ "from Post as p left join Comment as c ON p.id = c.post.id group by p.id order by "+ orderParam;
return postList = session.createQuery(query,PostDTO.class).getResultList();
}

How do you format a datetime field in a SelectList in MVC?

I'm creating a new SelectList object and concatenating 2 fields, one is a string and the other is a DateTime. Basically I'm building a dropdownlist displaying the name and date of an event. When I try running the code I get the error ' LINQ to Entities does not recognize the method 'System.String ToShortDateString()' method, and this method cannot be translated into a store expression.'
Any help would greatly be appreciated.
ViewBag.EventKey = new SelectList((from e in db.Events where e.Active == true select new { e.PKey, EventInfo = e.Name + " " + e.EventDate.ToShortDateString() }), "Pkey", "EventInfo");
The problem is that you're calling .ToShortDateString in statement that is going to be translated to DB query. Try following:
ViewBag.EventKey = new SelectList((from e in db.Events where e.Active == true select e).ToArray().Select(e => new { e.PKey, EventInfo = e.Name + " " + e.EventDate.ToShortDateString() }), "Pkey", "EventInfo");

Automapper with linq how?

Ok, I'm really struggling with finding a good example of what I need to do. So, I'll ask here.
Let's say I have a entity class (EF) named Customer and a corresponding view-model class named CustomerViewModel.
Using AutoMapper, I have created the following mappings:
Mapper.CreateMap<CustomerViewModel, Customer>();
Mapper.CreateMap<Customer, CustomerViewModel>();
How would I modify the following code to make use of this mapping?
public static List<CustomerViewModel> GetCustomers()
{
using (var context = new GCSBaseEntities())
{
var query = from c in context.Customers
select new CustomerViewModel
{
CompanyName = c.CompanyName,
Id = c.Id,
EmailAddress = c.EmailAddress,
FirstName = c.FirstName,
LastName = c.LastName,
MiddleName = c.MiddleName,
ModifiedDate = c.ModifiedDate,
Phone = c.Phone,
SalesPerson = c.SalesPerson,
Suffix = c.Suffix,
Title = c.Title,
FullName = c.FirstName + " " + c.LastName
};
return query.ToList();
}
}
Thanks in advance.
When you register your mappings, you must provide any complex mapping operations that have to occur. In your case, I believe all your properties match up, except for FullName = c.FirstName + " " + c.LastName. Here's how your Customer-to-CustomerViewModel mapping should look:
Mapper.CreateMap<Customer, CustomerViewModel>()
.ForMember(custVm => custVm.FullName,
mapper => mapper.MapFrom(cust => cust.FirstName + " " + cust.LastName));
You'll have to figure out how to shove the FullName prop from the ViewModel back into the FirstName & LastName fields on the EF class, though. But when you decide how to implement it, follow the pattern from above for the other mapping.
Your query can now be MUUUCH smaller:
using (var context = new GCSBaseEntities())
{
return from c in context.Customers
select Mapper.Map<CustomerViewModel>(c);
}
Figured it out. In order to avoid the aforementioned error, you have to Add the call the .AsEnumerable() after Customers like so:
return from c in context.Customers.AsEnumerable()
select Mapper.Map<CustomerViewModel>(c);
I got this from this thread: LINQ and AutoMapper

Linq get all fields from select along with dynamic column

I have such Linq, I would like to get all records from Orders table and also add new dynamic field. The code below do not work. What is correct syntax?
user.dcOrders.Select(p =>p, new { FullName = p.FirstName + " " + p.LastName })
You'll need to list out all the columns.
Alternatively you could add a new property to whatever class dcOrders is. It should be specified as a partial class so you can add the FullName property to a new file so it doesn't get overwritten when the .designer.cs file is regenerated.
So something like
public partial class Orders
{
public string FullName { get { return this.FirstName + " " + this.LastName; } }
}
Be sure to add this to a separate file not the .designer.cs file. (I'm assuming LINQ to SQL here).
Then you don't need to do any special select, because FullName will already exist as a property on the object. You can just use it directly.
Try this:
var names = user.dcOrders.Select(p => new {
User = p,
FullName = p.FirstName + " " + p.LastName
});

NHibernate 3.0 IQueryable selecting ghost column

I'm getting a strange error when running what appears to be a simple query.
return (from x in session.Query<Contact>()
.Where(x => x.Id == 10)
select new ContactIndexViewModel
{
Id = x.Id,
Name = x.BasicInfo.FirstName + " " + x.BasicInfo.LastName,
Filters = x.Filters
}).FirstOrDefault();
Is generating the following SQL
select
contact0_.[Id] as col_0_0_,
contact0_.[BasicInfoFirstName] as col_1_0_,
contact0_.[BasicInfoLastName] as col_2_0_,
. as col_3_0_,
filters1_.[Id] as column1_16_,
filters1_.Criteria1 as Criteria2_16_,
// .. .more filters1_ fields
filters1_.ContactId as ContactId16_
from
[MyServer].[dbo].[Contact] contact0_
inner join [MyServer].[dbo].[Filter] filters1_
on contact0_.[Id]=filters1_.ContactId
where
contact0_.[Id]=#p0
Notice the fourth column being selected. BasicInfo is a component and the select (in the query) includes all the fields defined in the ViewModel.
I am not having any other problems with the Contact or Filter objects in other parts of the application. Contact -> Filter has a one to many relationship.
Any idea's on how to debug or what may cause this?
UPDATE
If I remove the reference to Filters in the select, the problem goes away.
UPDATE Relevant Mappings
Contact
public partial class ContactMap : ClassMap<Contact>
{
/// <summary>Initializes a new instance of the <see cref="ContactMap"/> class.</summary>
public ContactMap()
{
Table("[MyServer].[dbo].[Contact]");
OptimisticLock.Version();
DynamicUpdate();
LazyLoad();
Id(x=>x.Id)
.Access.CamelCaseField(Prefix.Underscore)
.Column("[Id]")
.GeneratedBy.Identity();
Version(x=>x.RecordVersion)
.Access.CamelCaseField(Prefix.Underscore)
.Column("[RecordVersion]")
.CustomSqlType("timestamp")
.Not.Nullable()
.UnsavedValue("null")
.CustomType("BinaryBlob")
.Generated.Always();
Map(x=>x.Active).Access.CamelCaseField(Prefix.Underscore);
// other scalar properties
Component(x0=>x0.BasicInfo, m0=>
{
m0.Map(x1=>x1.FirstName).Column("[BasicInfoFirstName]").Access.CamelCaseField(Prefix.Underscore);
m0.Map(x1=>x1.LastName).Column("[BasicInfoLastName]").Access.CamelCaseField(Prefix.Underscore);
// other scalar properties
});
// other relationships
HasMany(x=>x.Searches)
.Access.CamelCaseField(Prefix.Underscore)
.Cascade.AllDeleteOrphan()
.Fetch.Select()
.Inverse()
.LazyLoad()
.KeyColumns.Add("ContactId");
}
}
Search
public partial class SearchMap : ClassMap<Search>
{
public SearchMap()
{
Table("[MyServer].[dbo].[Search]");
OptimisticLock.Version();
DynamicUpdate();
LazyLoad();
Id(x=>x.Id)
.Access.CamelCaseField(Prefix.Underscore)
.Column("[Id]")
.GeneratedBy.Identity();
Map(x=>x.Controller).Not.Nullable().Access.CamelCaseField(Prefix.Underscore);
Map(x=>x.Module).Not.Nullable().Access.CamelCaseField(Prefix.Underscore);
Map(x=>x.Name).Column("[Name]").Not.Nullable().Access.CamelCaseField(Prefix.Underscore);
References(x=>x.Contact)
.Access.CamelCaseField(Prefix.Underscore)
.Cascade.All()
.Fetch.Select()
.Columns("ContactId");
HasMany(x=>x.DataFilters)
.Access.CamelCaseField(Prefix.Underscore)
.Cascade.AllDeleteOrphan()
.Fetch.Select()
.Inverse()
.LazyLoad()
.KeyColumns.Add("SearchId");
}
}
Did you map Filters with FetchMode.Join?
By the way, it may be easier to create the ContactIndexViewModel in memory, with the trade off that it fetches too many columns from the database. On the other side, Get doesn't flush the session, which may be performance relevant.
var contact = session.Get<Contact>(10);
return new ContactIndexViewModel
{
Id = contact.Id,
Name = contact.BasicInfo.FirstName + " " + contact.BasicInfo.LastName,
Filters = contact.Filters
};
Your mapping for the table is unusual to me.
Table("[MyServer].[dbo].[Contact]");
Normally the server name is provided during configuration, the schema is stated separately, and the delimiters ("[...]") are set by NHibernate. I would map it as:
Schema("dbo");
Table("Contact");
That may be causing a parsing problem leading to the odd select. If that's not it, then I think it's a bug -- NHibernate should never issue a select without a table alias and column name.

Resources