Linq Nhibernate left join - linq

A Theft has an action property
This is the query i'm trying to get NHibernate.Linq to produce:
SELECT * FROM `thefts`
LEFT JOIN memberThefts
ON thefts.id = memberThefts.theftId AND memberThefts.memberId = 1
I want to get a list of all the thefts where action.memberId == some number or just null if it doesn't find a row, simple as a query yet it's been giving me a nightmare all day!
thefts = session.Query<Theft>()
.Fetch(x => x.action)
.Where(x => x.action.memberId == member.id)
.ToList();
This executes the following SQL:
select theft0_.id as id9_0_,
memberthef1_.memberId as memberId7_1_,
theft0_.name as name9_0_,
theft0_.chance as chance9_0_,
memberthef1_.theftId as theftId7_1_,
memberthef1_.availableTime as availabl3_7_1_
from thefts theft0_
left outer join memberThefts memberthef1_
on theft0_.id = memberthef1_.theftId,
memberThefts memberthef2_
where theft0_.id = memberthef2_.theftId
and memberthef2_.memberId =1 /* ?p0 */
The theft class:
public class Theft
{
public virtual byte id { get; set; }
public virtual string name { get; set; }
public virtual byte rank { get; set; }
public virtual byte chance { get; set; }
public virtual MemberTheft action { get; set; }
...
And it's mapping:
public TheftMap()
{
Table("thefts");
Id(x => x.id);
Map(x => x.name);
Map(x => x.id);
Map(x => x.chance);
References(x => x.action)
.Nullable()
.PropertyRef(x => x.theftId)
.Column("id");
}
Any solution will do HQL, QueryOver etc

It can't be done using the LINQ provider, but you can do it with QueryOver. Something along the lines of:
MemberTheft memberAlias = null;
var result = Session.QueryOver<Theft>()
.Left.JoinQueryOver(x => x.action, () => memberAlias)
.Where(() => memberAlias.memberId == member.id);
Edit: Updated Query.

Related

EF Navigating across tables with .Include

I want to extend this query..
var itinerary = context.Itineraries
.Include(i => i.ItineraryDays)
.Include(i => i.ItineraryStartDates)
.Where(i => i.Id == Id).FirstOrDefault();
.. to include 3 tables which are accessible through ItineraryDays using the following navigation properties to traverse.
ItineraryDay>> public virtual Listing Listing { get; set;} (ItineraryDay.ListingId === Listing.Id)
Listing>> public virtual Port Port { get; set; } (Listing.PortId === Port.Id)
Port>> public virtual Country Country { get; set; } (Port.CountryId = Country.Id)
regards, Guy
in that case, you have to replace
.Include(i => i.ItineraryDays)
by
.Include(i => i.ItineraryDays.Listing.Port.Country)
And you will have the 4.
As they are "single" properties, that will do the trick.
EDIT
oh, as ItineraryDays in Itinerary (could have guess, by the way) seems to be a collection , think you have to do
.Include(i => i.ItineraryDays.Select(id => id.Listing.Port.Country))

How to cast to a generic list from the lambda expression result

I have a class structure like below.
ObservableCollection<Group> deviceCollection = new ObservableCollection<Group>();
public class Group
{
public string Name { get; set; }
public List<TargetSelectionStructure> TargetCollection { get; set; }
}
public class TargetSelectionStructure
{
public string ItemId { get; set; }
public string Name { get; set; }
public bool IsGroup { get; set; }
}
From the observable collection object deviceCollection. I need to get the collection which matches with IsGroup property as false. So I have written like
var currentStruct = deviceCollection.Where(d => d.TargetCollection.Any(t => t.IsGroup == false));
Now the currentStruct should contain the collection basically List<TargetSelectionStructure>. I am unable to cast the currentStruct to the type of List<TargetSelectionStructure>.
How can I solve this?
You can't cast it, because currentStruct is an IEnumerable<Group>.
I think you query needs to look like this:
var currentStruct = deviceCollection.SelectMany(x => x.TargetCollection)
.Where(x => !x.IsGroup).ToList();
This returns all TargetSelectionStructure instances from all Groups that have IsGroup == false.
Your question is not entirely clear. It is possible to interpret your question in a second way: You want to have all TargetSelectionStructure instances from a Group if at least one of them has IsGroup == false.
To achieve this, you would use this query:
var currentStruct = deviceCollection.Where(x => x.TargetCollection
.Any(y => !y.IsGroup))
.SelectMany(x => x.TargetCollection)
.ToList();

Telerik MVC Grid - Group by Date

I'm trying to use Telerik MVC Grid for an application which requires lots of filtering and grouping... On every model I have, it has a property DateTime for storing CreationDate. Sometimes when showing the grid to the user, time isn't important. Also, I had to use ViewModels to avoid circular references since I'm using LINQ.
The problem comes when resorting or grouping results by date. If I use the CreationDate field as a Datetime on my ViewModel and then give it Format on the View to show only date, it sorts fine, works fine, but when grouping it groups using the whole datetime value, so there wont never be anything groupedby. If I use the CreationDate as a string in the ViewModel, it shows fine the first time but will give error if resorting or grouping by date.
Here's the code I have for this case:
VIEWMODEL:
public class CenterViewModel
{
public int Id { get; set; }
public string Name{ get; set; }
public string CityName { get; set; }
public string Phone{ get; set; }
public string CreationDate { get; set; }
public bool Active { get; set; }
}
CONTROLLER:
[GridAction]
public ActionResult AjaxIndex()
{
var model = repository.GetAllRecords()
.Select(o => new CenterViewModel
{
Id = o.Id,
Name = o.Name,
CityName= o.City.Name,
Phone = o.Phone,
CreationDate = o.CreationDate .ToShortDateString(),
Active = o.Active
});
return View(new GridModel
{
Data = model
});
}
public ActionResult Index()
{
return View();
}
VIEW:
#model IEnumerable<CenterViewModel>
#(Html.Telerik().Grid<CenterViewModel>()
.Name("Grid")
.DataKeys(keys =>
{
keys.Add(p => p.Id);
})
.Columns(columns =>
{
columns.Bound(o => o.Name);
columns.Bound(o => o.CityName);
columns.Bound(o => o.Phone);
columns.Bound(o => o.CreationDate).Width(200);
columns.Bound(o => o.Active).Width(100)
.DataBinding(dataBinding => {
dataBinding.Ajax().Select("AjaxIndex", "Centers", null);
})
.Pageable()
.Sortable()
.Groupable()
.Filterable())
The above code would work only for the first load of data, when you resort or group by date it will throw the following exception: "Method 'System.String ToShortDateString()' has no supported translation to SQL." which makes sense, but, I think my intention is pretty clear now.
Does anyone know how to solve this issue? Thanks in advance,
One thing you could try is in your model to use a date that removes the time element. Then in the view, format the date.
VIEWMODEL:
public DateTime CreationDate { get; set; }
CONTROLLER:
var model = repository.GetAllRecords()
.Select(o => new CenterViewModel
{
Id = o.Id,
Name = o.Name,
CityName= o.City.Name,
Phone = o.Phone,
CreationDate = new DateTime(o.CreationDate.Year, o.CreationDate.Month, o.CreationDate.Day),
Active = o.Active
});
VIEW:
columns.Bound(o => o.CreationDate).Width(200).Format("{0:MM/dd/yyyy}");

Linq query to find items that could be within a range

I have an object Invoice which belongs to an Area:
public class Invoice : IEntity, IValidatableObject
{
...
public virtual int? AreaId { get; set; }
...
// Navigation properties
public virtual Area Area { get; set; }
...
}
I also have a User object which can belong to multiple areas:
public class User : IEntity, INamedType
{
...
//Navigation properties
public virtual ICollection<Area> Areas { get; set; }
...
}
What I'm wanting to achieve is to get for a user all the invoices that belong to any of their areas. I tried writing it but it's not even close to right:
var invoices = _db.Invoices.Where(x => x.AreaId == user.Areas.Contains(z => z.Id));
Can anyone help me with this query?
var invoices = _db.Invoices.Where(x => user.Areas.Any(z => z.Id == x.AreaId));
I think something like that should work:
var invoices = _db.Invoices.Where(x => user.Areas.Any(z => z.ID == x.AreaId))

NHIbernate (3.1) - Linq group by then order by count issue

I am trying to get a group by followed by an order by count to work but I keep getting a 'Antlr.Runtime.NoViableAltException' being thrown.
Here is the simplest error case I can create.
var results = ArticleStatsRepository.GetAll().GroupBy(x => x.Article.ArticleId)
.OrderBy(x => x.Count());
ArticleStatsRepository.GetAll() returns an IQueryable of ArticleStats.
public class ArticleStats
{
public virtual int ArticleStatsId { get; set; }
public virtual Article Article { get; set; }
public virtual User Viewer { get; set; }
public virtual ArticleStatTypeEN ArticleStatType { get; set; }
public virtual DateTime DateTime { get; set; }
}
Ultimately I would like the following query to execute.
return ArticleStatsRepository.GetAll()
.Where(x => x.DateTime > DateTime.Now.Add(-timeSpan))
.Where(x => x.ArticleStatType == ArticleStatTypeEN.View)
.GroupBy(x => x.Article.ArticleId)
.Select(x => new { ArticleId = x.Key, Count = x.Count() })
.OrderByDescending(x => x.Count)
.Join(ArticleRepository.GetAll(), artStats => artStats.ArticleId, articles => articles.ArticleId, (artStats, articles) => new MostPopularArticleResult { ArticleId = artStats.ArticleId, ArticleTitle = articles.Content.Title, Count = artStats.Count });
I am using Fluent NHibernate 1.2.0.712 which references NHibernate: 3.1.0.4000.
Any help would be greatly appreciated!
Regards
Steve
Update: This is how I got round the issue. Not perfect as I didn't want to start using HQL with its QueryOver and would of liked to stick to IQueryable throughout.
public virtual IQueryable<MostPopularArticleResult> GetMostPopularArticleResults(TimeSpan timeSpan, IQueryable<Article> filteredArticles, List<ArticleStatTypeEN> types, int take)
{
var results = ArticleStatsRepository.GetAllQueryOver().Where(x => x.DateTime > DateTime.Now.Add(-timeSpan));
results = results.Where(x => x.ArticleStatType.IsIn(types));
var articleIdsWithCounts = results.Select(
Projections.Group<ArticleStats>(x => x.Article.ArticleId),
Projections.Count<ArticleStats>(x => x.Article.ArticleId))
.OrderBy(Projections.Count<ArticleStats>(x => x.Article.ArticleId))
.Desc
.Take(take)
.List<object[]>()
.Select(x => new { ArticleId = (int)x[0], Count = (int)x[1] });
return articleIdsWithCounts.Join(filteredArticles, artStats => artStats.ArticleId, articles => articles.ArticleId, (artStats, articles) => new MostPopularArticleResult { ArticleId = artStats.ArticleId, ArticleTitle = articles.Content.Title, Count = artStats.Count })
.AsQueryable();
}
As #mynkow and #Chris S said that was a NH 3.1 issue. You could update library version or look at thoose question about simila problem:
http://sourceforge.net/p/nhibernate/mailman/nhibernate-issues/
Nhibernate 3 Linq throws Antlr.Runtime.NoViableAltException
NHibernate Query, using OfType and Subqueries
NHibernate 3.1 migration problem with Linq

Resources