Here what I am trying to do is to convert List of Bson Document to the list of Class. The main purpose of doing so is to filter the data from the list of Json data. I am using MongoDb for my database and C# for handling data. I have stored some data in MongoDb and trying to filter the data using FilterDefinition like this:
PROCESS 1
FileContext context = new FileContext();
var collection = context.Db.GetCollection<BsonDocument>("DBCollection");
var builder = Builders<BsonDocument>.Filter;
FilterDefinition<BsonDocument> Filter = builder.Eq("FileName", fileDetail.FileName) & builder.Eq("FileNumber", fileDetail.FileNumber.ToString());
var list = await collection.Find(Filter).ToListAsync();
In this way I am not been able to get the data in list. Therefore, I tried the other way like this:
PROCESS 2
FileContext context = new FileContext();
var collection = context.Db.GetCollection<BsonDocument>("DBCollection");
var list = await collection.Find(_ => true).ToListAsync();
List<MyClass> objList = null;
foreach (var item in objList)
{
objList = new List<MyClass>();
objList.Add(BsonSerializer.Deserialize<MyClass>(item));
}
if(objList.Count >0)
{
int count = objList.Where(x => x.FileName == "SOME_FILE_NAME" && x.FileNumber == 1).Count();
}
This way I am able to get the data and able to filter data as well but I know this is not good programming at all as this will have lots of waiting time if the size of data increases in future.
Here my questions are:
What is wrong in PROCESS 1?
How to Convert List<BsonDocument> to List<MyClass>?
How to filter List<BsonDocument>?
var collection = context.Db.GetCollection<BsonDocument>("DBCollection");
should be:
var collection = context.Db.GetCollection<MyClass>("DBCollection");
That way you should be able to use the Find method to check your FileName and FileNumber using something like:
var objList = await collection.Find(x => x.FileName == "FILENAMEHERE" && x.FileNumber == 1).ToListAsync();
Related
I've been trying to Sort a collection using MongoDB SortDefinition but whenever I "sort" the collection via a single sort definition, all I get returned is an empty list. However, when I use more than one sort definitions, it returns values.
var TestSort1 = Builders<Scenario>.Sort.Ascending("Name");
var filtered1 = await _context
.DbCollection
.Find(_ => true)
.Sort(TestSort1)
.ToListAsync();
The code above returns an empty list. However, the code below works fine.
var TestSort2 = Builders<Scenario>.Sort.Ascending("Name").Ascending("Owner");
var filtered2 = await _context
.DbCollection
.Find(_ => true)
.Sort(TestSort2)
.ToListAsync();
Is it possible to use a single SortDefinition to sort the collection? Or maybe I am using the SortDefinition wrong?
Maybe you should try using the fluent C# syntax for creating aggregation pipelines...
var collection = database.GetCollection<FiltroCond>("dbCENTRAL");
var filter = Builders<FiltroCond>.Filter.Eq(x => x.PartnerId, cliente)
& Builders<FiltroCond>.Filter.Eq(x => x.TP_PESSOA, 3)
& Builders<FiltroCond>.Filter.Gte(x => x.FG_ATIVO, true);
var result = collection.Aggregate().Match(filter)
.Project(p => new FiltroCond { CD_CLIENTE = p.CD_CLIENTE, ID_CENTRAL = p.ID_CENTRAL, FANTASIA = p.FANTASIA })
.SortBy(p => p.ID_CENTRAL).ToList();
It works fine to me.
I am using the Linq.Dynamic Library and EF6. I am attempting to select only the fields from a database that my user selects.
However, all that is returned is a List<object>, I have attempted to Cast<dynamic>, and every way I can think of, but no matter what the object has 0 fields.
I have also tried explicitly declaring as an IEnumerable and that too was unsuccessful, and was unable to call .ToList(), without first calling Cast<T> which too was unsuccessful.
When converting one of the objects to string I get: "{filenumber=345400, custom2=, custom3=, custom6=4076995332, custom8=4072121417}".
The data is being returned I simply cannot cast it to the appropriate type.
var query = cmax.dbases
.Where(w => statuses.Any(a => w.statusname == a) && portfolios.Any(a => w.portfolio == a))
.Select(string.Format("new ({0})", string.Join(",", fields)))
.Take(Math.Min((int) takeAmount, count - taken));
var take = await query.ToListAsync();
take.ForEach(data => {
var type = take.GetType();
var properties = type.GetProperties();
var propCount = properties.Count();
properties.ToList().ForEach(prop => {
var name = prop.Name;
});
});
In one of my use cases I have converted the results to List<string[]> through an extension for IQueryable. As I know my column order in Select("New (columnNames...) "), I could easily figure out which one is which.
so here is the code of the extension
public static IList<string[]> ToStringArray(this IQueryable queryFinal)
{
var query = (IQueryable<dynamic>)queryFinal;
IList<dynamic> data = query.ToList();
System.Reflection.PropertyInfo[] props = null;
if (data.Count > 0) props = data[0].GetType().GetProperties();
if (props == null) return new List<string[]>();
/*I do other things using reflection here*/
return data.Select(d => props.Select(p => (p.GetValue(d, null) ?? string.Empty).ToString()).OfType<string>().ToArray()).ToList();
}
use it as
var result = query.ToStringArray();
The only viable solution I found was to manually parse the data in the string:
take.ForEach(data =>
{
var dbtrData = new DebtorData();
var cleaned = data.ToString().Replace("{", "").Replace("}", "");
var pairs = cleaned.Split(',');
pairs.ToList().ForEach(pair =>
{
var key = pair.Split('=')[0].Replace(" ", "");
var value = pair.Split('=')[1];
//USEDATA
}
});
I have searching for a while now, but couldn't find how to query from public view. For example, I have predefined public view called Active Accounts and I want data from it.
So far I only know this way, but that not include any views:
using (var xrm = new XrmServiceContext("Xrm"))
{
var activeAccounts = from a in xrm.AccountSet
where a.StateCode == 0
select new { a.Id, a.Name };
// TODO ...
}
But I would like to do it like this (not working, ActiveAccountsView not exist, it's pseudo):
using (var xrm = new XrmServiceContext("Xrm"))
{
var activeAccounts = from a in xrm.ActiveAccountsView
select new { a.Id, a.Name };
// TODO ...
}
Is this even possible?
The query definitions of public views are stored in the savedquery entity, that can be queried using common techniques.
Out-of-the-box views are stored with a fixed ID, so querying Active Accounts on the OrganizationServiceContext object could be done in the following way:
private static IEnumerable<Entity> GetActiveAccounts(OrganizationServiceContext serviceContext)
{
string fetchXml = serviceContext
.CreateQuery("savedquery")
.Where(sq =>
sq.GetAttributeValue<Guid>("savedqueryid") == new Guid("00000000-0000-0000-00AA-000010001002"))
.Select(sq => sq.GetAttributeValue<string>("fetchxml"))
.First();
var request = new RetrieveMultipleRequest
{
Query = new FetchExpression(fetchXml)
};
var response = (RetrieveMultipleResponse) serviceContext.Execute(request);
return response.EntityCollection.Entities;
}
It is not possible to use LINQ here. LINQ relies on the QueryExpression class, but does not implement all its capabilities (OUTER JOIN is a painful omission for example). So, while it is possible to convert a LINQ query to a QueryExpression, the other way around is not.
Paging can be applied by editing the Fetch XML string, but if that is too much hassle, you can also consider to convert the Fetch XML to a QueryExpression and apply paging on that object:
private IEnumerable<Entity> GetActiveAccounts(int pageNumber)
{
string fetchXml = _serviceContext
.CreateQuery("savedquery")
.Where(sq =>
sq.GetAttributeValue<Guid>("savedqueryid") == new Guid("00000000-0000-0000-00AA-000010001002"))
.Select(sq => sq.GetAttributeValue<string>("fetchxml"))
.First();
var conversionRequest = new FetchXmlToQueryExpressionRequest
{
FetchXml = fetchXml
};
var response = (FetchXmlToQueryExpressionResponse)_serviceContext.Execute(conversionRequest);
response.Query.PageInfo = new PagingInfo { Count = 1, PageNumber = pageNumber };
var queryRequest = new RetrieveMultipleRequest
{
Query = response.Query
};
var result = (RetrieveMultipleResponse) _serviceContext.Execute(queryRequest);
return result.EntityCollection.Entities;
}
Additional advantage of the QueryExpression vs. Fetch XML is that it is processed in a bit more efficient way.
The very same can be done with user defined views; these views are stored in the userquery entity. The only difference here is you cannot rely on a fixed view ID. Instead you would need to filter your query on querytype, name, returnedtypecode, ownerid and/or other criteria.
Dynamics CRM also has an OrganizationRequest that allows you to execute the savedquery immediately. However, it returns its result as a resultset XML string, so you would still need to deserialize the response. (A nice example can be found here.) Also, I am not sure if it is possible to limit the result set to a specific page when using the ExecuteByIdSavedQueryRequest:
var request = new ExecuteByIdSavedQueryRequest
{
EntityId = new Guid("00000000-0000-0000-00AA-000010001002")
};
var response = (ExecuteByIdSavedQueryResponse)serviceContext.Execute(request);
string resultset = response.String;
I have a linq query that works when it I had a list of a single value now that I change to having a List that has several properties I need to change the where clause
So this works:
List<string> etchList = new List<string>();
etchList.Add("24");
var etchVect = (from vio in AddPlas
where etchList.Any(v => vio.Key.Formatted.Equals(v))
let firstOrDefault = vio.Shapes.FirstOrDefault()
where firstOrDefault != null
select new
{
EtchVectors = firstOrDefault.Formatted
}).ToList();
However I have a new hard coded list (which will represent incoming data:
List<ExcelViolations> excelViolations = new List<ExcelViolations>();
excelViolations.Add(new ExcelViolations
{
VioID = 24,
RuleType = "SPACING",
VioType = "Line-Line",
XCoordinate = 6132,
YCoordinate = 10031.46
});
So the NEW Linq query looks like this, but is obviously will not work as
AddPlas is a List and so using this other list of excelviolations, I wish to have it do where on each one of the properties in the excelviolations list
var etchVect = (from vio in AddPlas
where excelViolations.Any(vioId => vio.Key.Formatted.Equals(vioId))
let firstOrDefault = vio.Shapes.FirstOrDefault()
select new
{
EtchVectors = firstOrDefault.Formatted
}).ToList();
Now, since this is a list within a list, I would like to do something like add in each of the properties
so for example:
where excelViolations.VioID.Any(vioId => vio.Key.Formatted.Equals(vioId))
However that is not possible, but you see that I'm trying to access the property of VioID that is in the excelViolations and match it to the Key which is in vio list
Just change this line
where excelViolations.Any(vioId => vio.Key.Formatted.Equals(vioId))
to
where excelViolations.Any(excelVio => vio.Key.Formatted.Equals(excelVio.VioID))
then i thought it will works
I am using LINQ-to-Entities and have loaded up a Northwind Database (with LazyLoading=true).
var db = new NorthwindEntities();
var result = db.Orders.Where(x => x.CustomerID == "ANATR").First();
DataGridView1.DataSource = result;
The above code doesn't show up any items (one in this particular case) in the DataGridView. What am I doing wrong?
(If I remove the 'First()' it works fine and gives me several items)
The result is not a collection, that's why, you can not list it. First is a single object.
var db = new NorthwindEntities();
var result = db.Orders.Where(x => x.CustomerID == "ANATR").First();
DataGridView1.DataSource = result;
since result isn't a Collection this won't work you can use
var results =Enumerable.Repeat(result, 1);
To create single item in a list to do this or also
var results = new List<Order>() { result };
Will also work
And then bind to results instead of result
Your result is actually a single object not a collection of objects.
Try adding the result to an empty list.