I can't directly cast object in my Entity Framework query using ValueInjecter - casting

I'm trying to use ValueInjecter to map my entities to my DTOs in my asp.net core project.
Could someone explain me why this works:
var list = _context.Assets
.ToList();
var vm = list
.Select(a => new ViewModel().InjectFrom(a))
.Cast<ViewModel>()
.ToList();
return vm;
But this doesn't:
var list = _context.Assets
.Select(a => new ViewModel().InjectFrom(a))
.Cast<ViewModel>()
.ToList();
return list;
Is this a ValueInjecter bug? Am I doing something wrong?
Would Automapper solve this? I strongly prefer valueinjecter syntax compared to Automapper.
Thanks for your help!
Edit:
#Chris Pratt: Thanks for your quick answer. But why would it work when I map properties manually like the example below. I'm still applying this mapping to the IQueryable interface not in-memory.
Then why this works?
var vm = _context.Assets
.Select(a => new ViewModel
{
Id = a.Id,
Code = a.Code
})
.AsNoTracking()
.ToList();
return vm;

I haven't used ValueInjector, but my guess is that it comes down to the Select being applied in-memory in the first example and to the query in the second example. Dynamic mapping is not something that can be done at the database level, and specifically, EF must be able to translate the things you pass in Select, Where, etc. into SQL. It will not be able to do so with the ValueInjector code, and hence cannot construct a query to satisfy the LINQ expression. You do not have this issue in the first example, because you pull then entities from the database first, and then you map those in-memory instances.
For what it's worth, AutoMapper would have the same problem here, so it's not technically a mapping provider problem - just one of where the operation is going to be run (i.e. in-memory vs. at the database).

Related

REALM MOBILE PLATFORM sync problems resolution

I have linked list in Realm DB like
ABCD
Each item is Realm object like
{name,next item}
So if I change list on device 1 offline to
ACBD
and on device 2 to
ADBC
and sync after that I get synced DB but wrong cycled list
A -> D -> B -> D .....
How can I solve this problem?
Is there possibility to get synced objects after sync on clients and to correct lists before realm Results notifications will be launched?
Update.
I also tried to use such model for hierarchical lists
class MList: Object {
dynamic var name = ""
let items = List<MItem>()
}
class MItem: Object {
dynamic var name = ""
let subitems = List<MItem>()
}
I have used data
A
B
1.
A
-B
2.
B
-A
After sync but list lost all items. So such data struct is unsuitable for my task.
Alright, I see the problem.
Manually maintaining a linked list structure unfortunately won't work, because Realm sees each link update as a regular property update without knowledge about the item's position in the list. Therefore the list updates cannot be merged in the expected way when multiple participants update the list, and the result will be duplicates, cycles, or leaked objects.
Instead, I suggest you use Realm's built-in list type, which will merge correctly. You will still have a problem related to the parent field in your data model, whereby if two participants change the value, the last one to do so will "win". I'm not sure what your exact use case is, so this may or may not be fine. Notably it probably won't be fine if you perform tree rotations, in which case you will end up leaking objects from the graph or creating unexpected cycles.
The best long-term solution is for Realm to introduce a proper CRDT tree type, but so far there hasn't been demand for this. If trees are a fundamentally requirement in your data model, I suggest creating a feature request for CRDT trees in our GitHub repository.
Can you use Realm's own lists? They have quite an elaborate merging logic that supports element moves/reorderings: https://realm.io/docs/javascript/latest/#list-properties
Now I have the model
class MList: Object {
dynamic var name = ""
dynamic var firstItem: PLItem?
}
class MItem: Object {
dynamic var name = ""
dynamic var next: PLItem?
dynamic var parent: PLItem?
}
I use "next" to order list and "parent" to create the tree structure.

Cant retrieve local records from store using Ember Data

I am trying to retrieve records which have already been loaded into the store by using this line in a controller:
var allProducts = this.store.all('product');
However, this is returning a strange object (see screenshot). When I call length on it, the result is "undefined." I have used the Chrome Ember inspector to confirm that records have indeed been loaded into Product before the above line of code is run. I thought since store.all returns a recordarray I could iterate over it immediately unlike a promise. Where am I going wrong please?
The strange object that is returned is a record array. This is important so that Ember can set up observers for arrays that are loaded. I believe this is what is causing your confusion. See more specifics in the docs:
It's important to note that DS.RecordArray is not a JavaScript array.
It is an object that implements Ember.Enumerable. This is important
because, for example, if you want to retrieve records by index, the []
notation will not work--you'll have to use objectAt(index) instead.
You will have to look at the documention for DS.RecordArray but you should be able to iterate over it using the forEach method. See the ember array documentation for more details.
The issue was that I was trying to iterate over the recordarray using a traditional for loop. Seems that a) recordarray cannot return length and 2) one must use a forEach loop to iterate over it, which is what I had initially did but dropped because forEach does not support break or continue.
Ahh promises! :)
You should be able to do this:
var allProducts = this.store.all('product').then(function(products) {
return products;
});

How to perform search for multiple terms in Sitecore 7 ContentSearch API?

I am exploring the new Sitecore.ContentSearch "LINQ to Sitecore" API in Sitecore 7. It is my understanding that Sitecore recommends using the new LINQ API over the existing Sitecore.Search API, however, I am struggling to perform even the simplest of queries.
Take for instance the following search query: "hello world".
Using the Sitecore.Search API, the terms "hello world" would typically be passed through a QueryParser which would result in documents matching the word "hello" OR "world". Documents containing both terms would be scored higher that those with just one.
How does one perform this same query using LINQ?
Here's what I have tried:
var results = SearchContext.GetQueryable<MyResultItem>();
var terms = searchTerm.Split(' ');
// Not supported exception
results = results.Where(r => terms.Any(t => r.Content.Contains(r)));
// Close, but performs an "AND" between terms, and does not appear
// to score documents properly
foreach (var term in terms)
{
results = results.Where(r => r.Content.Contains(t));
}
UPDATE
I am convinced that I am missing something really simple. Surely with all the work that went into the new search API, this simple use case wasn't overlooked... right?
As a workaround, I tried opening the default sitecore_web_index using the existing SearchManager, however, this does not work.
Unfortunately, I have had to resort to the existing API until I can figure this out. I will be sure to update this question with my findings.
UPDATE 2
I found the Sitecore.ContentSearch.Utilities.LinqHelper class which partially solves the problem. You can use it to dynamically build a query similar to a BooleanQuery in Lucene.Net, however, it's options are limited and it adds a bit of performance overhead.
All of the predicate builders I tried didn't work, however, Sitecore 7 ships with a PredicateBuilder of it's own that did the trick.
using Sitecore.ContentSearch;
using Sitecore.ContentSearch.Linq;
using Sitecore.ContentSearch.SearchTypes;
using Sitecore.ContentSearch.Utilities;
// Sitecore 7 (Update 1+): using Sitecore.ContentSearch.Linq.Utilities;
...
var index = ContentSearchManager.GetIndex("sitecore_web_index");
using (var context = index.CreateSearchContext())
{
var predicate = PredicateBuilder.True<SearchResultItem>();
foreach (var t in term.Split(' '))
{
var tempTerm = t;
predicate = predicate.Or(p => p.Content.Contains(tempTerm));
}
var results = context.GetQueryable<SearchResultItem>().Where(predicate).GetResults();
...
}
I think this is related to linq not to sitecore.
I don't test this but have a look at this article http://www.albahari.com/nutshell/predicatebuilder.aspx
You can also look at this documentation http://sdn.sitecore.net/upload/sitecore7/70/developer's_guide_to_item_buckets_and%20search_sc7-a4.pdf
I was able to use PredicateBuilder with Solr and implement queries including the OR operator. See http://www.nttdatasitecore.com/en/Blog/2013/November/Building-Facet-Queries-with-PredicateBuilder.aspx

Methods for filtering within a Doctrine results Collection?

I'm very new to Doctrine, so this might seem a rather obvious question to those more experienced.
I'm writing a data import tool that has to check every row being imported contains valid data. For example, the Row has a reference to a product code, I need to check that there is a pre-existing Product object with that code. If not, flag that row as invalid.
Now I can easily do something like this for each row.
$productCode = $this->csv->getProductNumber();
$product = $doctrine->getRepository('MyBundle:Product')->findOneBy(array('code' => $productCode ));
But that seems hideously inefficient. So I thought about returning the entire Product Collection and then iterating within that.
$query = $this->getEntityManager()->createQuery('SELECT p FROM MyBundle\Entity\Product p');
$products = $query->getResult();
All well and good, but then I've got to write messy loops to search for.
Two questions:
1). I was wondering if I'm missing some utility methods such as you have in Magento Collections, where you can search within the Collection results without incurring additional database hits. For example, in Magento this will iterate the collection and filter on the code property.
$collection->getItemByColumnValue("code","FZTY444");
2). At the moment I'm using the query below which returns an "rectangular array". More efficient, but could be better.
$query = $this->getEntityManager()->createQuery('SELECT p.code FROM MyBundle\Entity\Product p');
$products = $query->getResult();
Is there a way of returning a single dimensional array without have to reiterate the resultset and transform into a flat array, so I can use in_array() on the results?
If I understand your question correctly you want to filter an array of entities returned by getResult(). I had a similar question and I think I've figured out two ways to do it.
Method 1: Arrays
Use the array_filter method on your $products variable. Yes, this amounts to a "loop" in the background, but I think this is a generally acceptable way of filtering arrays rather than writing it yourself. You need to provide a callback (anonymous function in 5.3 preferred). Here is an example
$codes = array_filter($products, function($i) {
return $i->getCode() == '1234';
});
Basically in your function, return true if you want the result returned into $codes and false otherwise (not sure if the false is necssary, or if a void return value is sufficient).
Method 2: Doctrine's ArrayCollection
In your custom repository or where ever you are returning the getResult() method, you can instead return an ArrayCollection. This is found in the Doctrine namespace Doctrine\Common\Collections\. More documenation on the interface behind this method can be found here. So in this case you would have
$query = $this->getEntityManager()->createQuery('SELECT p FROM MyBundle\Entity\Product p');
$products = new ArrayCollection($query->getResult());
You can then use the filter() method on the array collection. Use it in a very similar way to the array_filter. Except it doesn't need a first argument because you call it like this: $products->filter(function($i) { ... });
The ArrayCollection class is an iterator, so you can use it in foreach loops to your hearts content, and it shouldn't really be different from an array of your products. Unless your code explicitly uses $products[$x], then it should be plug 'n' play*.
*Note: I haven't actually tested this code or concept, but based on everything I've read it seems legit. I'll update my answer if it turns out I'm wrong.
You can use another hydration mode. $query->getResult() usually returns a result in object hydration. Take a look at $query->getScalarResult(), which should be more suitable for your needs.
More info on the Doctrine 2 website.

Case sensitive LINQ to DataSet

I am having an issue with a strongly typed DataSet exhibiting case-sensitivity using LINQ to DataSet to retrieve and filter data. In my example project, I have created a strongly typed DataSet called DataSet1. It contains a single DataTable called Customers. To instantiate and populate, I create a couple of rows (notice the casing on the names):
// Instantiate
DataSet1 ds = new DataSet1();
// Insert data
ds.Customers.AddCustomersRow(1, "Smith", "John");
ds.Customers.AddCustomersRow(2, "SMith", "Jane");
Next, I can easily fetch/filter using the DataSet's built-in Select functionality:
var res1 = ds.Customers.Select("LastName LIKE 'sm%'");
Console.WriteLine("DataSet Select: {0}", res1.Length);
DataSet Select: 2
The trouble begins when attempting to use LINQ to DataSet to perform the same operation:
var res2 = from c in ds.Customers where c.LastName.StartsWith("sm") select c;
Console.WriteLine("LINQ to DataSet: {0}", res2.Count());
LINQ to DataSet: 0
I've already checked the instantiated DataSet's CaseSensitive property as well as the Customer DataTable's CaseSensitive property--both are false. I also realize that when using the Select methodology, the DataSet performs the filtering and the LINQ query is doing something else.
My hope and desire for this type of code was to use it to Unit Test our Compiled LINQ to SQL queries so I can't really change all the current queries to use:
...where c.LastName.StartsWith("sm", StringComparison.CurrentCultureIgnoreCase) select c;
...as that changes the query in SQL. Thanks all for any suggestions!
LINQ to DataSets still use normal managed functions, including the standard String.StartsWith method.
It is fundamentally impossible for these methods to be aware of the DataTable's CaseSensitive property.
Instead, you can use an ExpressionVisitor to change all StartsWith (or similar) calls to pass StringComparison.CurrentCultureIgnoreCase.
You could also use c.LastName.ToLower().StartsWith("sm" which will make sure you also retrieve lower cased entries. Good luck!