NOTE: This has been answered as duplicate in the comment below.
I am having trouble getting RIA Services to return the data I need and not more than the data I need. I have a parent object (Project) which contains a number of children. One is a Component (one Component per Project). Another is a ProjectParticipant which needs to be limited based on the ParticipantRole, and I also need to grab the Person information (related to ProjectParticipant).
Here is some code I had earlier tried:
public IQueryable<IMSModel.Project> GetProjectHierarchy(String id)
{
return this.ObjectContext.Projects
.Include("Component")
.Include("ProjectParticipants")
.Include("ProjectParticipants.Person")
.Where(p => p.Program.ProgramType.lookupName == "EVDBE" &&
p.ProjectOrgs.Any(po => po.orgId == id) &&
p.ProjectParticipants.Any(pp => (pp.postId == id)) &&
p.ProjectParticipants.Any(pp => pp.PersonStatus.lookupName == "A") &&
p.ProjectParticipants.Any(pp => pp.ParticipantRole.participantInd == "Y"))
.OrderBy(p => new { p.fiscalYear, p.title })
.OrderByDescending(p => p.fiscalYear);
}
This doesn't work too badly, but I end up getting ProjectParticipant objects that I do not want. What I really want to do is limit the ProjectParticipant objects to those that have ParticipantRole.participantInd == "Y".
I tried another possible syntax for this, which is as follows:
public IQueryable<IMSModel.Project> GetProjectHierarchy(String id)
{
return this.ObjectContext.Projects
.Include("Component")
.Join(this.ObjectContext.ProjectParticipants
.Include("ProjectParticipants.Person")
.Where(
pp => pp.ParticipantRole.participantInd == "Y" &&
pp.postId == id &&
pp.PersonStatus.lookupName == "A"
)
, p => p.id
, pp => pp.projectId
, (p, pp) => p )
.Where(p => p.Program.ProgramType.lookupName == "EVDBE"
&& p.ProjectOrgs.Any(po => po.orgId == id));
}
I would think that this would return something a lot closer to what I might want. The only issue is that I don't get anything back in my hierarchical tree view. Something was returned, as blank locations were created for each record, but my bindings are not displaying any information. The bindings for the first example do show data, whereas the bindings for the second (more limited result set as I am not using Any()) does not show data.
I have been banging my head against this one for quite some time now and cannot resolve. Any assistance would be great.
Related
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>());
I am trying to copy data from one list to other list (both lists are on different sites) along with lookup columns. But, I am getting an error for lookup field as:
Value does not fall within the expected range
Code works and data gets copied for other non-lookup fields. I tried every possible way including increasing List View Lookup Threshold and all possible ways of code but still error persists at ExecuteQuery().
Below is my code for lookup field:
if (field is FieldLookup && field.InternalName == "Country")
{
var CountryLookup = (item.FieldValues["Country"] as FieldLookupValue).LookupValue.ToString();
var CountryLookupId = (item.FieldValues["Country"] as FieldLookupValue).LookupId.ToString();
FieldLookupValue flvRDS = new FieldLookupValue();
flvRDS.LookupId = int.Parse(CountryLookupId);
itemToCreate["Country"] = flvRDS;
itemToCreate.Update();
destContext.ExecuteQuery();
}
Help is really appreciated.
I assume item is the new ListItem you're trying to create on your target list.
But you're never in fact reading any value from field here! So basically, you're trying to set your new FieldLookup.LookupId with the item["Country"].LookupId, which should logically be empty at this moment.
Here's a method I use to retrieve a lookup field ListItem from a value, feel free to modify it to fit your need, since I don't know how you want to retrieve it (SPList is an alias for Microsoft.SharePoint.Client.List).
private ListItem GetLookupItem(FieldLookup lookupField, string lookupValue)
{
string mappingField = lookupField.LookupField;
Microsoft.SharePoint.Client.List lookupList = Context.Web.Lists.GetById(new Guid(lookupField.LookupList));
Context.Load(lookupList);
Context.ExecuteQuery();
ListItemCollection libListItems = lookupList.GetItems(CamlQuery.CreateAllItemsQuery());
Context.Load(libListItems, items => items.Include(
itemlookup => itemlookup.Id,
itemlookup => itemlookup[mappingField]));
Context.ExecuteQuery();
foreach (ListItem mappedItem in libListItems)
{
object mappedField = mappedItem[mappingField];
if (mappedField != null && mappedField.ToString().Equals(lookupValue))
return mappedItem;
}
return null;
}
Now that you have the corresponding ListItem, you can set your item.LookupId with its Id:
if (field is FieldLookup && field.InternalName == "Country")
{
FieldLookupValue flvRDS = new FieldLookupValue();
flvRDS.LookupId = GetLookupItem(field as FieldLookup, "France").Id; // here, dunno how you get your country's name
itemToCreate["Country"] = flvRDS;
itemToCreate.Update();
destContext.ExecuteQuery();
}
Feel free to add some more previous code if you want an answer more suited for your specific issue.
In a controller for a page in tornado-cms, I do the following:
def res = Service.tornado.articles([ articleCategoryPath: "boker/ny"]);
Service.tornado.loadFullArticles(res);
res.sort { a,b ->
b.props.year <=> a.props.year
}
tornado.small_articles = res;
Or, shorter:
tornado.small_articles = Service.tornado.articles([
articleCategoryPath: "boker/ny",
full: true ])
.sort { a, b -> b.props.year <=> a.props.year };
This fills the content box small_articles with the all the articles from a specific folder "boker/ny" reversely sorted by the article prop year.
It works fine, but is it possible to save the changes made to the content box tornado.small_articles so that the resulting list of articles is also visible from the GUI? Something like Service.tornado.saveChangesToPageContentBox(page, content_box_nr, tornado.small_articles);?
Start by removing the articles currently bound to the small_articles box like this:
Integer containerId = <id-of-small-articles-container>;
Service.tornado.getPageBindings(page.id).each { binding ->
if (binding.containerId == containerId)
Service.tornado.deletePageBinding(binding);
}
Then add new bindings for the articles you have collected:
tornado.small_articles.each {
Service.tornado.addPageBinding(new ArticlePageContainer(page.id, it.id, containerId));
}
You should not do this on every request to the given page, but rather update the list when the content changes or by some other, less frequent criteria.
I have four fields. Lets call them a, b, c and d. I need to validate them.
Error is when:
One til three fields are not empty;
Error is not when:
All fields are not empty,
All fields are empty;
Any neat solution here? Thanks in advice.
Edit:
Only relationships are that all four variables are prefixed with event_. It gives me event_name, event_description etc..
Edit #2:
At the moment I have something like...
if (
!empty($values['event_date'])
&& !empty($values['event_time'])
&& !empty($values['event_name'])
&& !empty($values['event_description'])
) {
It checks that all fields are filled up and then, if that's true, adds event.
As I said before, I need to display user-friendly error when some field isn't filled up (for example, user had forgot to enter description). Anyway, when all fields are filled up (it means - all okay) or when no fields are filled up (it means - user ignores event adding and don't want to add one) - no error should be displayed.
I could write code with 16 'if' statements, but isn't there any better way? :)
This isn't beautiful, but as long as you have something unique about the fields you want to check (such as "event_..."), you could loop through the variable array ($values, $_POST, etc) and check only the fields that matter. Then, you can easily check for an all or none situation.
Here is a quick example:
$total = 0;
$filled = 0;
foreach($values as $field => $val) {
if(strpos($field,'event_') === 0) {
$total++;
if( ! empty($val)) {
$filled++;
}
}
}
if($filled == 0 OR $total == $filled) {
//PASS VALIDATION
} else {
//FAIL VALIDATION
}
Is there a relationship between one of the entered values and the none entered values??
could you just parse it as an empty value?
if ( ! isset($post->a) ) $post->a = '';
We are using accountability pattern for organizational structure. I using linq to nhibernate to find some departments and position but I have two problem.
var query =
Repository<Party>.Find(p => p.IsInternal == true)
.Where(p => p.Parents.Any(c => c.Parent.PartyId == id))
.Where(p =>
(
p.PartyType.PartyTypeId == (int)PartyTypeDbId.Department &&
_secretariat.Departments.Select(c => c.PartyId).Contains(p.PartyId)
)
||
(
p.PartyType.PartyTypeId == (int)PartyTypeDbId.Position &&
p.Children.Any(c =>
c.AccountabilityType.AccountabilityTypeId == (int)AccountabilityTypeDbId.TenurePersonOfPosition &&
((Person)c.Child).UserName != null)
)
);
First : I got 'Unhandled Expression Type: 1003' for this part of query : '_secretariat.Departments.Select(c => c.PartyId).Contains(p.PartyId)'
and I got Property not found 'UserName'
We have many complex queries i think we need to use stored procedure.
Sorry for bad Inglish!
One nice thing that you can do with LINQ is break your queries into multiple parts. Since you are building an expression tree that won't get executed until the results are enumerated, you don't have to do it all in one line (like SQL).
You can even make some reusable "filters" that you can apply to IQueryable. These filter functions accept an IQueryable as an argument, and return one as a result. You can build these as extension methods if you like (I like to).
As for your immediate problem, you may want to try a join on _secretariat instead of attempting a subquery. I've seen them work in scenarios where subqueries don't.
In addition to Lance's comments you might want to look at a compiled Linq query and breaking up some of the responsibilties to follow SOLID principles.
I've just also found out that there are issues with the Contains when containing Any linq methods. However, Any seems to work well within Any, hence:
_secretariat.Departments.Select(c => c.PartyId).Any(x => x == p.PartyId)