LINQ to query Service Fabric Reliable Collections? - linq

Are there any plans in adding LINQ support for Reliable Collections on Service Fabric? Does anyone know of any extensions that can enable this? It seems like this was possible in a previous API version but not anymore.

On a reliable dictionary, you can use CreateEnumerableAsync to create an async enumerable. (Documentation here.)
Next, you can create linq queries by using Eli's extension methods here.
Example from gist:
var accounts = await (await accountNames.CreateLinqAsyncEnumerable(txn))
.Where(x => x.Value.IndexOf(name, StringComparison.InvariantCultureIgnoreCase) >= 0)
.SelectAsync(async x => new Account
{
Id = x.Key,
Name = x.Value,
Data = (await accountData.TryGetValueAsync(txn, x.Key)).Value
})
.ToList();

Related

Exception: when trying to use Enumerable.Any Method with Mobile Services query

I have a mobile app build with Xamarin Forms and I'm using Offline Data Sync in Azure Mobile Apps, to enable offline sync in my mobile application
so,
I have two tables
PurchaseOrders
PurcahseOrderDetails
public IMobileServiceSyncTable<PurchaseOrders> PurchaseOrdersTable;
public IMobileServiceSyncTable<PurchaseOrderDetails> PurchaseOrderDetailsTable;
and I want to sync the records in the PurchaseOrders Table based on UserId
and then sync the records in PurchaseOrderDetails Table based on Id of PurcahseOrder
To do that I'm trying this
Get Purchase Orders based on User Id
var purchaseOrders = (await GetAllPurchaseOrdersAsync(syncFromServer:true, userId)).ToList();
// in sync method
await PurchaseOrdersTable.PullAsync(queryName, PurchaseOrdersTable.CreateQuery().Where(w => w.Userid == userId));
When I'm trying to get Purchase Order Details based on Id in the list of PurchaseOrders
await PurchaseOrderDetailsTable.PullAsync(queryName,
PurchaseOrderDetailsTable.CreateQuery().Where(pod => purchaseOrders.Any(po => po.Id == pod.PoId)));
I get the exception below
'value(System.Collections.Generic.List`1[ProjectName.Models.PurchaseOrder]).Any(po => (po.Id == pod.PoId))' is not supported in a 'Where' Mobile Services query expression.
Can I get an explanation about the error above and how to solve it?
If your mobile data is backed by table service, then Any is not a supported LINQ operator (see: https://learn.microsoft.com/en-us/rest/api/storageservices/query-operators-supported-for-the-table-service) so that might be source of the exception.
Since PurchaseOrder doesn't contain a collection of PurchaseOrderDetail, one workaround I can think of is to iterate on purchaseOrders and select from purchaseOrderDetails.
var poDetails = new List<PurchaseOrderDetail>();
foreach (var po in purchaseOrders)
{
var poDetail = await PurchaseOrderDetails.PullAsync(queryName, PurchaseOrderDetailsTable.CreateQuery().Where(pod => po.Id == pod.PoId);
poDetails.Add(poDetail);
}

Problems with findEntity()

I am having a problem similar to Botframework findEntity() issue.
I have created a node.js botframework app using the azure interface. I am using the azure ide for development (to keep things simple).
The relevant code is:
// Main dialog with LUIS
var recognizer = new builder.LuisRecognizer(LuisModelUrl);
var intents = new builder.IntentDialog({ recognizers: [recognizer] })
/*
.matches('<yourIntent>')... See details at http://docs.botframework.com/builder/node/guides/understanding-natural-language/
*/
.matches('Help',(session, args) => {
var entities = args.entities;
var itype = builder.EntityRecognizer.findEntity(args.entities, 'ItemTypes');
session.send(args.entities[0]["entity"]);
session.send(args.entities[0]["type"]);
session.send('How may I assist you? ' + JSON.stringify(args));
session.send('Value of entity (didnt match) you said: \'%s\'.', itype);
})
the findEntity function returns null in itype (at least that is what I see in the session.send results.
I tried using both args.entities and args.intents.entities, no change.
When I look at the results of the args.entities[0]["entity"] and [type] I do get values. The results of the JSON.stringify are below (also showing it is finding the entity).
How may I assist you?
{"score":0.970185757,"intent":"Help","intents":[{"intent":"Help","score":0.970185757},{"intent":"Joke","score":0.0711096451},{"intent":"Greeting","score":0.0438234434},{"intent":"None","score":0.0408537947},{"intent":"Goodbye","score":0.04074517}],"entities":[{"entity":"stapler","type":"ItemTypes","
I'm assuming there is more but that it was cut off by the chat window.
I'm new to every technology involved and will take any help I can get.

Nest - Reindexing

Elasticsearch released their new Reindex API in Elasticsearch 2.3.0, does the current version of NEST (2.1.1) make use of this api yet? If not, are there plans to do so?
I am aware that the current version has a reindex method, but it forces you to create the new index. For my use case, the index already exists.
Any feedback/insights will be greately appricated. Thnx!
This kind of question is best asked on the github issues for NEST since the committers on the project will be able to best answer :)
A commit went in on 6 April to map the new Reindex API available in Elasticsearch 2.3.0, along with other features like the Task Management API and Update By Query. This made its way into NEST 2.3.0
NEST 2.x already contains a helper for doing reindexing that uses scan/scroll under the covers and returns an IObservable<IReindexResponse<T>> that can be used to observe progress
public class Document {}
var observable = client.Reindex<Document>("from-index", "to-index", r => r
// settings to use when creating to-index
.CreateIndex(c => c
.Settings(s => s
.NumberOfShards(5)
.NumberOfReplicas(2)
)
)
// query to optionally limit documents re-indexed from from-index to to-index
.Query(q => q.MatchAll())
// the number of documents to reindex in each request.
// NOTE: The number of documents in each request will actually be
// NUMBER * NUMBER OF SHARDS IN from-index
// since reindex uses scan/scroll
.Size(100)
);
ExceptionDispatchInfo e = null;
var waitHandle = new ManualResetEvent(false);
var observer = new ReindexObserver<Document>(
onNext: reindexResponse =>
{
// do something with notification. Maybe log total progress
},
onError: exception =>
{
e = ExceptionDispatchInfo.Capture(exception);
waitHandle.Set();
},
completed: () =>
{
// Maybe log completion, refresh the index, etc..
waitHandle.Set();
}
);
observable.Subscribe(observer);
// wait for the handle to be signalled
waitHandle.Wait();
// throw the exception if one was captured
e?.Throw();
Take a look at the ReIndex API tests for some ideas.
The new Reindex API is named client.ReIndexOnServer() in the client to differentiate it from the existing observable implementation.

Get raw query from NEST client

Is it possible to get the raw search query from the NEST client?
var result = client.Search<SomeType>(s => s
.AllIndices()
.Type("SomeIndex")
.Query(query => query
.Bool(boolQuery => BooleanQuery(searchRequest, mustMatchQueries)))
);
I'd really like to debug why I am getting certain results.
The methods to do this seem to change with each major version, hence the confusing number of answers. If you want this to work in NEST 6.x, AND you want to see the deserialized request BEFORE it's actually sent, it's fairly easy:
var json = elasticClient.RequestResponseSerializer.SerializeToString(request);
If you're debugging in Visual Studio, it's handy to put a breakpoint right after this line, and when you hit it, hover over the json variable above and hit the magnifying glass thingy. You'll get a nice formatted view of the JSON.
You can get raw query json from RequestInformation:
var rawQuery = Encoding.UTF8.GetString(result.RequestInformation.Request);
Or enable trace on your ConnectionSettings object, so NEST will print every request to trace output
var connectionSettings = new ConnectionSettings(new Uri(elasticsearchUrl));
connectionSettings.EnableTrace(true);
var client = new ElasticClient(connectionSettings);
NEST 7.x
Enable debug mode when creating settings for a client:
var settings = new ConnectionSettings(connectionPool)
.DefaultIndex("index_name")
.EnableDebugMode()
var client = new ElasticClient(settings);
then your response.DebugInformation will contain information about request sent to elasticsearch and response from elasticsearch. Docs.
For NEST / Elasticsearch.NET v6.0.2, use the ApiCall property of the IResponse object. You can write a handy extension method like this:
public static string ToJson(this IResponse response)
{
return Encoding.UTF8.GetString(response.ApiCall.RequestBodyInBytes);
}
Or, if you want to log all requests made to Elastic, you can intercept responses with the connection object:
var node = new Uri("https://localhost:9200");
var pool = new SingleNodeConnectionPool(node);
var connectionSettings = new ConnectionSettings(pool, new HttpConnection());
connectionSettings.OnRequestCompleted(call =>
{
Debug.Write(Encoding.UTF8.GetString(call.RequestBodyInBytes));
});
In ElasticSearch 5.x, the RequestInformation.Request property does not exist in ISearchResponse<T>, but similar to the answer provided here you can generate the raw query JSON using the Elastic Client Serializer and a SearchDescriptor. For example, for the given NEST search query:
var results = elasticClient.Search<User>(s => s
.Index("user")
.Query(q => q
.Exists(e => e
.Field("location")
)
)
);
You can get the raw query JSON as follows:
SearchDescriptor<User> debugQuery = new SearchDescriptor<User>()
.Index("user")
.Query(q => q
.Exists(e => e
.Field("location")
)
)
;
using (MemoryStream mStream = new MemoryStream())
{
elasticClient.Serializer.Serialize(debugQuery, mStream);
string rawQueryText = Encoding.ASCII.GetString(mStream.ToArray());
}
Before making Request, from Nest Query - For Nest 5.3.0 :
var stream = new System.IO.MemoryStream();
elasticClient.Serializer.Serialize(query, stream );
var jsonQuery = System.Text.Encoding.UTF8.GetString(stream.ToArray());
Edit: It's changed from from Nest 6.x, and you can do below:
var json = elasticClient.RequestResponseSerializer.SerializeToString(request);
on nest version 6 use
connextionString.DisableDirectStreaming();
then on response.DebugInformation you can see all information.
Use result.ConnectionStatus.Request.
When using NEST 7 and you don't want to enable debug mode.
public static string GetQuery<T>(this IElasticClient client, SearchDescriptor<T> searchDescriptor) where T : class
{
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
client.RequestResponseSerializer.Serialize(searchDescriptor, ms);
return Encoding.UTF8.GetString(ms.ToArray());
}
}
While it's possible to get raw request/response through code, I find it much easier to analyze it with fiddler.
The reason is that I can easily analyze raw request, response, headers, Full URL, execution time - all together without any hassle of code changes.
Here's some reference links in case someone unfamiliar with fiddler wants to check details:
#1 https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/logging-with-fiddler.html
#2 NEST 1.0: See request on Fiddler
#3 https://newbedev.com/how-to-get-nest-to-work-with-proxy-like-fiddler
How about using Fiddler ?! :)

LINQ CRM 2011 Update - Create

I notice the the CRM moderator David Jennaway on the technet forum states that you can't use LINQ to update/Create records in CRM 2011 see here http://social.microsoft.com/Forums/en-IE/crmdevelopment/thread/682a7be2-1c07-497e-8f58-cea55c298062
But I have seen a few threads that make it seem as if it should work. Here is my attempt which doesn't work. Any ideas why not?
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
OrganizationServiceContext orgContext = new OrganizationServiceContext(service);
EntityState state = new EntityState();
state = EntityState.Changed;
var counter = from c in orgContext.CreateQuery<pcx_entitycounter>()
where c.pcx_name.Contains("pcx_candidate")
select new pcx_entitycounter
{Id = c.Id,
pcx_name = c.pcx_name, pcx_Sequence = c.pcx_Sequence, pcx_Prefix = c.pcx_Prefix
};
foreach (var c in counter)
{
string prefix = c.pcx_Prefix.ToString(); ;
string sequence = c.pcx_Sequence.ToString();
c.pcx_Sequence = c.pcx_Sequence + 1;
c.EntityState = state;
**service.Update(c);** //FAILS HERE
}
In my experience, it's been difficult-to-impossible to retrieve an entity from the Context, update it, then use the Service to save the changes. It has caused me headaches figuring it out!
Since your retrieval code uses a query from the Context, all of those entities should be attached to the Context and their states are being tracked. Thus you need to use the Context's method for updating:
foreach (var c in counter) {
string prefix = c.pcx_Prefix.ToString(); ;
string sequence = c.pcx_Sequence.ToString();
c.pcx_Sequence = c.pcx_Sequence + 1;
// Use the Context to save changes
orgContext.UpdateObject(c);
orgContext.SaveChanges();
}
Since a lot of my code will retrieve entities in different ways (i.e. Service or Context) depending on the situation, I have developed a simple method that knows how to update the entity correctly. To expand on your example, you might have an update method that looks like:
public void UpdatePcxEntityCounter(pcx_entitycounter c) {
if (!orgContext.IsAttached(c)) {
service.Update(c);
}
else {
orgContext.UpdateObject(c);
orgContext.SaveChanges();
}
}
This assumes both orgContext and service are available at a scope above that of the method. Otherwise, they'd have to be passed as additional parameters.
Without seeing the difficult its difficult to discern what the issue is but have you tried using orgContext.UpdateObject(c); before doing the update step? Also, not sure why you are assigning the prefix and sequence to local variables within your loop since they don't appear to be being used. Its possible that you are getting a SOAP Exception or something for assigning values that don't work. Do you have any plugins registered on the entity?
See the following links for possible resolutions -
How to update a CRM 2011 Entity using LINQ in a Plugin?
http://social.microsoft.com/Forums/en-US/crmdevelopment/thread/7ae89b3b-6eca-4876-9513-042739fa432a

Resources