complex entityframework query - entity-framework-5

I have two tables:
NewsRooms ( NrID[int] , NrName [string]);
RawNews( RnID [int], NrID[string]);
realtion is RawNews 1 * NewsRooms
so i use checkboxes for NewsRooms and save the ids as a string in RawNews like this ';1;2;'
now for example i have a list which contains some NrIDs . i want to select every RawNew which it's NrID contains any of the ids inside that list.
here is my code:
var temp = Util.GetAvailibleNewsRooms("ViewRawNews");
List<string> ids = new List<string>();
foreach (var item in temp)
ids.Add(";" + item.NrID.ToString() + ";");
model = db.RawNews.Where(r => r.NrID.Any(ids));
the line model = db.RawNews.Where(r => r.NrID.Any(ids)); is wrong and i don't know how to write this code. please guide me. thanks

ok guys, i found the solution myself so i post it here maybe some other guy need it some day!!
model = model.Where(r => ids.Any(i => r.NrID.Contains(i)));

Related

Getting pagination to work with one to many join

I'm currently working on a database with several one-to-many and many-to-many relationships and I am struggling getting ormlite to work nicely.
I have a one-to-many relationship like so:
var q2 = Db.From<GardnerRecord>()
.LeftJoin<GardnerRecord, GardnerEBookRecord>((x, y) => x.EanNumber == y.PhysicalEditionEan)
I need to return a collection of ProductDto that has a nested list of GardnerEBookRecord.
Using the SelectMult() technique it doesn't work because the pagination breaks as I am condensing the left joined results to a smaller collection so the page size and offsets are all wrong (This method: How to return nested objects of many-to-many relationship with autoquery)
To get the paging right I need to be able to do something like:
select r.*, count(e) as ebook_count, array_agg(e.*)
from gardner_record r
left join gardner_e_book_record e
on r.ean_number = e.physical_edition_ean
group by r.id
There are no examples of this in the docs and I have been struggling to figure it out. I can't see anything that would function like array_agg in the Sql object of OrmLite.
I have tried variations of:
var q2 = Db.From<GardnerRecord>()
.LeftJoin<GardnerRecord, GardnerEBookRecord>((x, y) => x.EanNumber == y.PhysicalEditionEan)
.GroupBy(x => x.Id).Limit(100)
.Select<GardnerRecord, GardnerEBookRecord>((x, y) => new { x, EbookCount = Sql.Count(y), y }) //how to aggregate y?
var res2 = Db.SelectMulti<GardnerRecord, GardnerEBookRecord>(q2);
and
var q2 = Db.From<GardnerRecord>()
.LeftJoin<GardnerRecord, GardnerEBookRecord>((x, y) => x.EanNumber == y.PhysicalEditionEan)
.GroupBy(x => x.Id).Limit(100)
.Select<GardnerRecord, List<GardnerEBookRecord>>((x, y) => new { x, y });
var res = Db.SqlList<object>(q2);
But I can't work out how to aggregate the GardnerEBookRecord to a list and keep the paging and offset correct.
Is this possible? Any workaround?
edit:
I made project you can run to see issue:
https://github.com/GuerrillaCoder/OneToManyIssue
Database added as a docker you can run docker-compose up. Hopefully this shows what I am trying to do
Npgsql doesn't support reading an unknown array or records column type, e.g array_agg(e.*) which fails with:
Unhandled Exception: System.NotSupportedException: The field 'ebooks' has a type currently unknown to Npgsql (OID 347129).
But it does support reading an array of integers with array_agg(e.id) which you can query instead:
var q = #"select b.*, array_agg(e.id) ids from book b
left join e_book e on e.physical_book_ean = b.ean_number
group by b.id";
var results = db.SqlList<Dictionary<string,object>>(q);
This will return a Dictionary Dynamic Result Set which you'll need to combine into a distinct id collection to query all ebooks referenced, e.g:
//Select All referenced EBooks in a single query
var allIds = new HashSet<int>();
results.Each(x => (x["ids"] as int[])?.Each(id => allIds.Add(id)));
var ebooks = db.SelectByIds<EBook>(allIds);
Then you can create a dictionary mapping of id => Ebook and use it to populate a collection of ebooks entities using the ids for each row:
var ebooksMap = ebooks.ToDictionary(x => x.Id);
results.Each(x => x[nameof(ProductDto.Ebooks)] = (x["ids"] as int[])?
.Where(id => id != 0).Map(id => ebooksMap[id]) );
You can then use ServiceStack AutoMapping Utils to convert each Object Dictionary into your Product DTO:
var dtos = results.Map(x => x.ConvertTo<ProductDto>());

ServiceStack OrmLite - Is it possible to do a group by and have a reference to a list of the non-grouped fields?

It may be I'm still thinking in the Linq2Sql mode, but I'm having a hard time translating this to OrmLite.
I have a customers table and a loyalty card table.
I want to get a list of customers and for each customer, have a list of express cards.
My strategy is to select customers, join to loyalty cards, group by whole customer table, and then map the cards to a single property on customer as a list.
Things are not named by convention, so I don't think I can take advantage of the implicit joins.
Thanks in advance for any help.
Here is the code I have now that doesn't work:
query = query.Join<Customer, LoyaltyCard>((c, lc) => c.CustomerId == lc.CustomerId)
.GroupBy(x => x).Select((c) => new { c, Cards = ?? What goes here? });
Edit: I thought maybe this method:
var q = db.From<Customer>().Take(1);
q = q.Join<Customer, LoyaltyCard>().Select();
var customer = db.SelectMulti<Customer,LoyaltyCard>(q);
But this is giving me an ArgumentNullException on parameter "key."
It's not clear from the description or your example code what you're after, but you can fix your SelectMulti Query with:
var q = db.From<Customer>()
.Join<Customer, LoyaltyCard>();
var results = db.SelectMulti<Customer,LoyaltyCard>(q);
foreach (var tuple in results)
{
Customer customer = tuple.Item1;
LoyaltyCard custCard = tuple.Item2;
}

Get entries count for a multiple category view (two categories) using a key (Xpages)

I am trying to retrieve the entries count for a multiple category view (two categories) using a key.
var db:NotesDatabase = session.getDatabase(sessionScope.serverPath,sessionScope.dbName);
var luview = db.getView(sessionScope.viewName);
var vec:NotesViewEntryCollection = null;
if (key != null) {
vec = luview.getAllEntriesByKey(key);
}
count = vec.getCount().toFixed()
The count being returned is incorrect. I have over 500 documents in the view. It seems to be returning just the document count (20) of the first sub-category.
I've found mention of this as a bug in the forums. I'm running this on a 9.0 server. Any pointers would be much appreciated.
What I would like is the total count - categories (25) + documents (500), that I can use in the repeat control limit.
Thanks,
Dan
I was able to resolve this by using the NotesViewNavigator.
var nav:NotesViewNavigator = v.createViewNavFromCategory(key);
var entry:NotesViewEntry = nav.getFirst();
while (entry != null) {
count = count + 1;
var tmpentry:NotesViewEntry = nav.getNext(entry);
entry.recycle();
entry = tmpentry;
}
Dan - If you can get the entry count into the view column with an #AllChildren... or #AllDecendents or something like that then using the view navigator you should be able to read that value in and not have to actually loop through all the documents.
Another way is to create a different view, could be hidden, and not categorize that second column. Then you're original solution should work I'd think.

Subsonic 3 - Sequence contains no matching element

I need help creating a LINQ SQL with subsonic. First the basics, this works fine:
var query = (from o in bd.concelhos
orderby o.descricao
select o);
var results = query.ToList<concelhos>();
However, I want to filter out some columns and I have created the following code:
var query = (from o in bd.concelhos
orderby o.descricao
select new FilteredConcelhos { id = o.idDistrito + "/" + o.idConcelho, descricao = o.descricao });
var results = query.ToList<FilteredConcelhos>();
which errors out in the ToList method with the description "Sequence contains no matching element"
Any help would be great with this...
update:
Turns out I was missing get set attributes in the newly declared class...
Like so
public class FilteredConcelhos
{
public string id { get; set; }
public string descricao { get; set; }
}
This clears the exception, but the resulting List is still all wrong (FilteredConcelhos.id contains nothing and FilteredConcelhos.descricao contains numbers)
Can you try to first execute the ToList and the select afterwards - then the select is performed via linq 2 objects!
Have you tried to work with an anonymous type?
var query = (from o in bd.concelhos
orderby o.descricao
select new { id = o.idDistrito + "/" + o.idConcelho,
descricao = o.descricao });
var results = query.ToList();
Unfortunately, this happened to me a lot. I'm not sure about the details of how Linq 2 Object works, but if you'll call ToList on the original object, like this:
from o in bd.concelhos.ToList()
...
It should do the trick.

Re-use of database object in sub-sonic

Yet another newbie SubSonic/ActiveRecord question. Suppose I want to insert a couple of records, currently I'm doing this:
using (var scope = new System.Transactions.TransactionScope())
{
// Insert company
company c = new company();
c.name = "ACME";
c.Save();
// Insert some options
company_option o = new company_option();
o.name = "ColorScheme";
o.value = "Red";
o.company_id = c.company_id;
o.Save();
o = new company_option();
o.name = "PreferredMode";
o.value = "Fast";
o.company_id = c.company_id;
o.Save();
scope.Complete();
}
Stepping through this code however, each of the company/company_option constructors go off and create a new myappDB object which just seems wasteful.
Is this the recommended approach or should I be trying to re-use a single DB object - and if so, what's the easiest way to do this?
I believe you can use the same object if you want to by setting its IsNew property to true, then change its data properties, save it again, repeat. Easy enough.
I 'm not so sure that you should bother, though. It depends on how bad those constructors are hurting you.
In my eyes assigning multiple objects to a single var is never a good idea but thats arguable. I would do this:
// Insert some options
company_option o1 = new company_option();
o1.name = "ColorScheme";
o1.value = "Red";
o1.company_id = c.company_id;
o1.Save();
company_option o2 = new company_option();
o2.name = "PreferredMode";
o2.value = "Fast";
o2.company_id = c.company_id;
o2.Save();
I you are worried about performance, that shouldn't be a issue unless you want to insert or update many objects at once. And again, in this case the time used for inserting the data takes longer than for the object creation.
If you are worried about performance you can skip the object creation and saving part completly by using a Insert query:
http://www.subsonicproject.com/docs/Linq_Inserts
db.Insert.Into<company_option>(
x => x.name,
x => x.value,
x => x.company_id)
.Values(
"ColorScheme",
"Red",
c.company_id
).Execute();

Resources