Get subcollection of MongoDB collection with C# driver based on search - c#

I have this project with https://github.com/Mech0z/Foosball/blob/master/Models/Old/PlayerRankHistory.cs
I have the following classes where PlayerRankHistory is saved in MongoDB, this contains a list of PlayerRankHistorySeasonEntry which each contains PlayerRankHistoryPlot.
I would then like to provide an email of a player and a seasonname and then only get the list PlayerRankHistoryPlots out as a list, but the code I have written is very slow and not faster than just providing only an email and getting much more data out
And as a side note, not sure how to write it to make it async
The query I have now is
public async Task<List<PlayerRankHistoryPlot>> GetPlayerRankEntries(string email, string seasonName)
{
var query = Collection.AsQueryable().SingleOrDefault(x => x.Email == email)
.PlayerRankHistorySeasonEntries.SingleOrDefault(x => x.SeasonName == seasonName).HistoryPlots;
List<PlayerRankHistoryPlot> result = query.ToList();
return result;
}
public class PlayerRankHistory
{
public PlayerRankHistory(string email)
{
Email = email;
PlayerRankHistorySeasonEntries = new List<PlayerRankHistorySeasonEntry>();
}
public Guid Id { get; set; }
public string Email { get; set; }
public List<PlayerRankHistorySeasonEntry> PlayerRankHistorySeasonEntries { get; set; }
}
public class PlayerRankHistorySeasonEntry
{
public PlayerRankHistorySeasonEntry(string seasonName)
{
SeasonName = seasonName;
HistoryPlots = new List<PlayerRankHistoryPlot>();
}
public string SeasonName { get; set; }
public List<PlayerRankHistoryPlot> HistoryPlots { get; set; }
}
public class PlayerRankHistoryPlot
{
public PlayerRankHistoryPlot(DateTime date, int rank, int eloRating)
{
Date = date;
Rank = rank;
EloRating = eloRating;
}
public DateTime Date { get; set; }
public int Rank { get; set; }
public int EloRating { get; set; }
}
An example of a document
{"_id":"AYU3e3Qgw0Gut1fngze80g==","Email":"someemail#gmail.com","PlayerRankHistorySeasonEntries":[{"SeasonName":"Season 1","HistoryPlots":[{"Date":"2020-01-10T12:24:12.511Z","Rank":11,"EloRating":1488},{"Date":"2020-01-13T12:51:41.597Z","Rank":12,"EloRating":1488},{"Date":"2020-01-15T11:11:43.223Z","Rank":10,"EloRating":1510},{"Date":"2020-01-15T11:11:45.049Z","Rank":8,"EloRating":1530},{"Date":"2020-01-15T12:14:58.042Z","Rank":9,"EloRating":1530},{"Date":"2020-01-15T12:14:59.886Z","Rank":8,"EloRating":1530}]}]}

I believe when you define Collection.AsQueryable().FirstOrDefault(), you are pulling all records in that collection and then filtering through them. You should use the Find() method that is provided by MongoDB C# driver to filter the records which is much faster as well.
Get the PlayerRankHistory objects based on the email address
From on the filtered records, only return the records that have the required season
Get the HostoryPlots for only the first match as list
Collection.Find(Builders<PlayerRankHistory>.Filter.Eq(x => x.Email, email))
.Select(y => y.PlayerRankHistorySeasonEntries.Where(z => z.SeasonName.Equals(seasonName)))
.FirstOrDefault()?.HistoryPlots
.ToList();

Related

How to query Entity Framework database for records between 2 dates, then return that information for display on screen

I have an Entity MVC app with a code-first database. I need to produce a search box to search between 2 dates and return the records between those dates.
I will call the method with jQuery/ajax and render the results in a table.
I've tried writing an API, with no success. I am not even sure if this is the correct way to go about it?
namespace Areometrex_Leaflet.Models
{
[Table ("Flight_Lines")]
public class Flight_line
{
[Key]
public string Swath_name { get; set; }
public string Flight_name { get; set; }
public string Swath_record { get; set; }
public string Flight_date { get; set; }
public decimal Start_lat { get; set; }
public decimal Start_long { get; set; }
public decimal End_lat { get; set; }
public decimal End_long { get; set; }
public decimal Altitude { get; set; }
public DateTime Time_start { get; set; }
public DateTime Time_end { get; set; }
public string Sensor { get; set; }
}
public class FlightLineContext : DbContext
{
public DbSet<Flight_line> Flight_Lines { get; set; }
}
}
This is my model that holds the objects in the database. I need to search the "Flight_date" property, that is held in my DB in this following format as an "nvarchar" :
17/11/2018 11:09:18 PM
My current API looks something like this:
[HttpPost]
public IEnumerable<Flight_line> SearchFlight_Line()
{
string start, end;
var rc = RequestContext;
var data = rc.Url.Request.GetQueryNameValuePairs();
{
start = data.FirstOrDefault().Value ?? string.Empty;
end = data.LastOrDefault().Value ?? string.Empty;
}
//db format: 17/11/2018 11:22:56 PM
var s = DateTime.Parse(start);
var flightSearch = new List<Flight_line>();
using (_context)
{
var sql = $"SELECT * FROM Flight_Lines WHERE Flight_Date BETWEEN '{start}' AND '{end}'";
flightSearch = _context.Flight_Lines.SqlQuery(sql).ToList<Flight_line>();
}
return flightSearch;
}
Ideally, I want to call this API with jquery/Ajax and return results to be displayed in an MVC view. My guess is that this is dead easy, but I am only learning and I'm running out of ideas. I would have thought this was really simple, but I am struggling to find the answers I am looking for online, which leads me to believe perhaps I am doing it wrong?
First of all, don't save dates as string in your database, you will just have problems later on.
Instead of:
public string Flight_date { get; set; }
Set it up as DateTime:
public DateTime Flight_date { get; set; }
As far as the query for searching flights go, you can try this. This will return a list of "Flight_line" objects which you can then return wherever you need.
DateTime start = DateTime.Now;
DateTime end = DateTime.Now.AddDays(7);
var flights = _context.Flight_line.Where(f => f.Flight_date >= start && f.Flight_date <= end).ToList();

C# Copy List items to Object Arrays

I have a list created from a stored procedure using EF6.0
I have also created 3 classes
public class Resas
{
public string todo{ get; set; }
public string prop { get; set; }
public string Code { get; set; }
public string statusCode { get; set; }
public string checkin { get; set; }
public string checkout { get; set; }
public List<profiles> profiles { get; set; }
}
public class profiles
{
public string action { get; set; }
public string id { get; set; }
public string profileType { get; set; }
public string title { get; set; }
public string firstName { get; set; }
public string middleName { get; set; }
public string lastName { get; set; }
public List<emailAddresses> emailAdresses { get; set; }
}
public class emailAddresses
{
public string emailAddress { get; set; }
public string emailAddress2 { get; set; }
}
I am doing a for-loop in the list and I need to get certain columns and put it in the array (I will put two, to keep it simple)
myEntities db = new myEntities();
List<rev_Result> revList = new List<rev_Result>();
revList.Clear();
revList = db.rev().ToList();
for (int i = 0; i < revList.Count(); i++)
{
Resas resas = new Resas();
profiles[] profiles = new profiles[1];
resas.todo = revList[i].todo;
resas.profiles[0].lastName = revList[i].lastName;
}
I am not familiar with C# as you can see from the psedo-code above.
I cannot figure out how to feed the Resas with data and then its Profile with data and then move to the next Resas entry.
Any help appreciated.
That's fairly simple using Linq:
Resas resas = new Resas();
resas.profiles = revList
.Select(x => new profiles() { action = x.todo, lastName = x.lastName })
.ToList();
What's happening here is: You loop through every entry in revList and get your wanted data structure (that's what Select is doing). x refers to the current entry in the loop, while the stuff to the right side of the arrow is you 'output': a new instance of your profiles class with the members assigned accordingly. The result of all of this is then converted to a list (before ToList(), think of it as a recipe to create the list) and assigned to resas.profiles.
By the way, a word on conventions: Usually, in C#, you would give your classes a name that starts with a capital letter. Also, your profiles class seems to contain data of exactly one profile, so a better name might be Profile. This also makes your data structure more clear, since List<profiles> seems to be a list of lists of profiles - but that's not what it actually is, is it?
Furthermore, Members generally start with a capital letter as well, so instead of action, lastName, you'd have: Action and LastName.
You can try with Linq. This is the code that should solve your issue, but Resas class doesn't have action property:
List<Resas> ls = revList.Select(x => new Resas() {
action = x.todo,
profiles = new List<profiles>() {
new profiles { lastName = x.lastName }
}
).ToList();
If you need to use action property of inprofiles` class:
List<Resas> ls = revList.Select(x => new Resas() {
profiles = new List<profiles>() {
new profiles {
action = x.todo,
lastName = x.lastName
}
}
).ToList();

How to insert data from MS Access to SQL after checking whether the data exists or not in the database using Entity Framework

Hopefully, the question header is clear enough to tell that I'm trying to read an Access file and upload the data to the database but checking at first whether the data already exists or not in the database.
I receive a daily report from a third-party company in Access file. I'm trying to create a windows service that will check for the file every morning, and if the new file exist, then it'll read and upload the data to the database. I'm trying to use Entity Framework. I read the article on Navigation Property, but I'm still confused on that; I never used navigation property before. Here are my models:
[Table("ClaimsTable")]
public partial class ClaimsTable
{
[Key]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int ClaimsID { get; set; }
public string EOPAID { get; set; }
public string AuthID { get; set; }
public string PAStatus { get; set; }
public string UserName { get; set; }
[DataType(DataType.Date)]
public DateTime EffectiveDate { get; set; }
[DataType(DataType.Date)]
public DateTime EndDate { get; set; }
public string RecordType { get; set; }
public int RxID { get; set; }
public int MemberID { get; set; }
public int PrescriberID { get; set; }
public string EditNumber { get; set; }
public string OriginSource { get; set; }
public string OriginMethod { get; set; }
/*
[ForeignKey("RxID")]
public virtual RxTable Prescription { get; set; }
[ForeignKey("MemberID")]
public virtual MembersTable Member { get; set; }
[ForeignKey("PrescriberID")]
public virtual PrescribersTable Prescriber { get; set; }
*/
}
...
[Table("MembersTable")]
public partial class MembersTable
{
[Key]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int MemberID { get; set; }
[DataType(DataType.Date), Display(Name= "Date of Birth"), DisplayFormat(DataFormatString="{0:mm/dd/yyyy}", ApplyFormatInEditMode=true)]
public DateTime DateofBirth { get; set; }
public string CardholderID { get; set; }
public string MemberFirstName { get; set; }
public string MemberLastName { get; set; }
//public virtual ICollection<AddressTable> Address { get; set; }
}
...
[Table("PrescribersTable")]
public partial class PrescribersTable
{
[Key]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int PrescriberID { get; set; }
public string NPI { get; set; }
public string PrescriberFirstName { get; set; }
public string PrescriberLastName { get; set; }
public string PhysicianType { get; set; }
//public ICollection<AddressTable> Address { get; set; }
}
....
using(OleDbConnection conn = new OleDbConnection(strDSN))
{
OleDbDataReader reader = null;
OleDbCommand command = new OleDbCommand("Select * from table", conn);
try
{
conn.Open();
}
catch(OleDbException o)
{
return o.Message;
}
reader = command.ExecuteReader();
List<ClaimsTable> Claim = new List<ClaimsTable>();
List<PrescribersTable> PrescriberInDB = new List<PrescribersTable>();
List<MembersTable> MembersInDB = new List<MembersTable>();
while(reader.Read())
{
PrescriberInDB = context.Prescribers.ToList();
MembersInDB = context.Members.ToList();
//CREATE LOCAL VARIABLE
string recordType = //check if the member and the prescriber exist in the database
int prescriberID = 0;
int prodID = 0;
int memberID = 0;
int drugID = 0;
int RxID = 0;
int claimID = 0;
//check if the member and the prescriber exist in the object before inserted into the database.
//the data will be uploaded to the database in bulk
//int newPrescriberID = Prescriber.Where(x => x.PrescriberFirstName == reader["Prescriber First Name"] && x.PrescriberLastName == reader["Prescriber Last Name"] && x.NPI == reader["Prescribing Physician"]).Select(x => x.PrescriberID).FirstOrDefault();
//int newMemberID = Member.Where(x => x.MemberFirstName == reader["Member First Name"] && x.MemberLastName == reader["Member Last Name"] && x.CardholderID == reader["CardhHolder"]).Select(x => x.MemberID).FirstOrDefault();
//insert the data if it doesn't exist
if(!PresciberExist(prescriberFirstName, prescriberLastName, npi, PrescriberInDB))
{
var prescriber = new PrescribersTable()
{
PrescriberFirstName = prescriberFirstName,
PrescriberLastName = prescriberLastName,
NPI = npi,
PhysicianType = physicianType
};
context.Prescribers.Add(prescriber);
context.SaveChanges();
prescriberID = GetPrescriberID(prescriberFirstName, prescriberLastName, physicianType, PrescriberInDB);
}
if(!MemberExist(memberFirstName, memberLastName, cardholderID, MembersInDB))
{
var member = new MembersTable()
{
MemberFirstName = memberFirstName,
MemberLastName = memberLastName,
CardholderID = cardholderID,
DateofBirth = dob
};
context.Members.Add(member);
context.SaveChanges();
memberID = GetMemberID(memberFirstName, memberLastName, cardholderID, MembersInDB);
}
}
}
return "Done uploading";
}
private bool MemberExist(string memberFirstName, string memberLastName, string cardholderID, List<MembersTable> MembersInDB)
{
return MembersInDB.Exists(x => x.MemberFirstName == memberFirstName && x.MemberLastName == memberLastName && x.CardholderID == cardholderID);
}
private bool PresciberExist(string prescriberFirstName, string prescriberLastName, string npi, List<PrescribersTable> PrescriberInDB)
{
return PrescriberInDB.Exists(x => x.PrescriberFirstName == prescriberFirstName && x.PrescriberLastName == prescriberLastName && x.NPI == npi);
}
The access database contains sensitive information, so I won't be able to add those data as an example. But here's a made up data for test. The data contains claims of patients.
Now, because there are many drugs and many claims for the same patient, and many patients for a prescriber.. I broke the database as it's shown above. Needs improvement? I welcome suggestion. The reason I did this is because I don't want my database to have repeated records which will make managing really troubling. This way, I'll have unique members in memberstable, unique prescribers in prescriberstable and so on and so forth.
The challenge I'm facing is that when I read the data from the access database, I'm assuming it reads row-wise. The code should first check the database whether the member exist or not. If it does, then get the member id which is an identity column. If it doesn't, then it should insert the member's info only, and then get the memberID. Similarly, I do the same thing with the prescriber's data. Check and insert if needed. This is the long way, and this is the only way I could figure out how to do it.
I know this is not a very good programming. I'm just an analyst who unfortunately has to do a lot of programming. And I'm learning as I go. With that said, there's a lot of ways to improve this code - I just don't know any. Can you point me to the right direction? Also, an example of how to check and insert the data if it doesn't exist in the database using navigation property. Currently, the data is read and uploaded just fine, but I saw in the database that it didn't quite do what I wanted it to do. It still added a couple of already existing members. I seriously needs some help.

RavenDB Includes still round-tripping to load included data

I have a parent/child relationship between a ProductFamily (the parent) and a list of subordinates (SaleItem). I am running the Ravendb Server locally with the server pulled up as a console app. When I query the Family data I am attempting to include the list of SaleItems in the session to avoid extra trips to the server. However on the console I see the subsequent calls to load the individual saleitem list for each family as I step through the foreach loop. I think I am doing something incorrectly and am puzzled as to what it may be. I am on day 2 of using RavenDB, so any handholding is appreciated.
Classes:
public class Family
{
public string Id { get { return string.Format(#"Families/{0}", this.FamilyID); } }
public int FamilyID { get; set; }
public string FamilyNumber { get; set; }
public string Description { get; set; }
public string[] SaleitemIds { get; set; }
public override string ToString()
{
return string.Format("Number:{0} - {1}", FamilyNumber, Description);
}
[JsonIgnore]
public List<SaleItem> SaleItems { get; set; }
}
public class SaleItem
{
public string Id { get { return string.Format(#"SaleItems/{0}", this.SaleItemID); } }
public int SaleItemID { get; set; }
public string Description { get; set; }
public override string ToString()
{
return string.Format("Number:{0} - {1}", SaleItemID.ToString(), Description);
}
}
And the code:
List<SearchTerm> searchterms = new List<SearchTerm>(){ new SearchTerm(){term="1009110922"}
,new SearchTerm(){term="1009112439"}
,new SearchTerm(){term="1009122680"}
,new SearchTerm(){term="1009124177"}
,new SearchTerm(){term="1009133928"}
,new SearchTerm(){term="1009135435"}
,new SearchTerm(){term="1009148000"}};
using (IDocumentSession session = documentStore.OpenSession())
{
var results = session.Query<Family>().Customize(o => o.Include<SaleItem>(s => s.Id)).Where(x => x.FamilyNumber.In(searchterms.Select(t => t.term).ToList()));
foreach (Family fam in results)
{
Console.WriteLine(fam.ToString());
fam.SaleItems = session.Load<SaleItem>(fam.SaleitemIds).ToList();
foreach (SaleItem si in fam.SaleItems)
{
Console.WriteLine(" " + si.ToString());
}
}
}
As I step through the code I see the calls to Get the list of saleitems on the line:
fam.SaleItems = session.Load<SaleItem>(fam.SaleitemIds).ToList();
I believe I have implemented something incorrectly, but I am new enough with this platform to accept that I could have simply misunderstood what the behavior would be. There are definitely cases where I do not want the Saleitem doc to be embedded in the Family doc, so that is not really an option in this case.
Doug_w,
Look at what you are including:
o.Include<SaleItem>(s => s.Id)
You probably want it to be:
o.Include<SaleItem>(s => s.SaleitemIds )

How to use Linq to select information from a collection into another concrete class I made?

I have the following class:
public class EntityJESummary
{
public int JEGroupingId { get; set; }
public int PartnershipId { get; set; }
public int JEId { get; set; }
public DateTime BookingDate { get; set; }
public DateTime EffectiveDate { get; set; }
public bool Allocated { get; set; }
public int JEEstate { get; set; }
public float Debit { get; set; }
public float Credit { get; set; }
public string JEComments { get; set; }
public EntityJESummary()
{
}
}
And here I'm using Linq to filter out DataRows from a source. I'm trying to fit information from this datasource into this new holder type class.
Any suggestions?
_dttMasterViewTransaction = dtsTransaction.Tables["tblTransaction"];
var datos = _dttMasterViewTransaction.AsEnumerable()
.Where(r => r["JEID"] == FundsID)
.Select(new EntityJESummary ???
Notice where I'm using r["foo"], I'm fetching data from each DataRow. I need to get specific rows and fit them into specific properties of my holder class.
Also, in the data table, there might be many rows for a single JEId, so I'd like to grab each Debit from each datarow and Sum it into the float Debit property.
Any suggestions would be very much appreciated. :)
Untested but try something similar to what you did with the Where clause:
var datos = _dttMasterViewTransaction.AsEnumerable()
.Where(r => r["JEID"] == FundsID)
.Select(r => new EntityJESummary {
JEGroupingId = r["JEGroupingId"],
PartnershipId = r["PartnershipId"],
.....
} );
You can make use of Object Initalizers.
_dttMasterViewTransaction = dtsTransaction.Tables["tblTransaction"];
var datos = _dttMasterViewTransaction.AsEnumerable()
.Where(r => r["JEID"] == FundsID).Select(r =>
new EntityJESummary() {
JEGroupingId = r["JEID"],
PartnershipId = r["PartnershipId"]
};

Categories

Resources