Retrieve Big data using EF - sql

I have two tables "Kelime"
public class Kelime
{
public int ID { get; set; }
public string Word { get; set; }
public DateTime Date { get; set; }
}
and "Anlam"
public class Anlam
{
public int ID { get; set; }
public string Meaning { get; set; }
public DateTime Date { get; set; }
public int Kelimesi_ID { get; set; }
[ForeignKey("Kelimesi_ID")]
public virtual Kelime kelime { get; set; }
}
Both tables contains more than 80k datas. I don't think they are very big but I am having problem on this query:
Repository<Kelime> _rk = new Repository<Kelime>();
Repository<Anlam> _ra = new Repository<Anlam>();
IEnumerable<int> kelimeIdler = _ra.All().Select(s => s.Kelimesi_ID).Distinct();
int _kelimecik= _rk.Find(w => !kelimeIdler.Contains(w.ID)).ID;
or Kelime _kelimecim = _rk.All().Where(w => !kelimeIdler.Contains(w.ID)).FirstOrDefault();
I am trying to take the "Kelime", "Kelime List" or its "id" it doesn't matter which are not in my "Anlam" table. There is a timeout when it comes to "contains" part. I tried to write non clustered index but it doesn't accept subquery. What should I do to achieve what I want? Thank you very much.

private static DataContext _context;
public static DataContext ContextOlustur()
{
if (_context == null)
{
_context = new DataContext();
}
return _context;
}
Adding this pattern to my data context class solved my problem. Because my queries used two different context that's why it was getting problem to connect database and got time out. This pattern prevents creating another context.

Related

Querying a table that relates to multiple entity types

So currently I have an application model of:
Note -> Thing
(A note can relate to many things)
A thing can be numerous entities (for this example lets use Computer & Car)
e.g
Note -> Computer
-> Car
So right now, I have the schema of
Note -> ComputerNote -> Computer
Note -> CarNote -> Car
The problem is that because the entity links are in separate tables, it requires a new query to be written rather than just using filtering in the WHERE clause.
Ideally it would be nice to have an EntityId & EntityTypeId column & on the Note table that would hold the primary key of the related entity and the type of the entity. Thus application logic could look for all Car notes where the car is x without a separate query for each type, but.. this would mean I lose referential integrity. Is there a better way, or is what I have suggested an acceptable design?
Entity Framework Model's:
public partial class Note
{
public Note()
{
NoteComputer = new HashSet<NoteComputer>();
NoteCar = new HashSet<NoteCar>();
NoteThing = new HashSet<NoteThing>();
}
public int Id { get; set; }
public string Value { get; set; }
public string CreatedByUserId { get; set; }
public DateTime CreatedDateTime { get; set; }
public ICollection<NoteComputer> NoteComputer { get; set; }
public ICollection<NoteCar> NoteCar { get; set; }
public ICollection<NoteThing> NoteThing { get; set; }
}
public partial class NoteCar
{
public int Id { get; set; }
public int NoteId { get; set; }
public int CarId { get; set; }
public Car Car { get; set; }
public Note Note { get; set; }
}
public partial class NoteComputer
{
public int Id { get; set; }
public int NoteId { get; set; }
public int ComputerId { get; set; }
public Computer Computer { get; set; }
public Note Note { get; set; }
}
public partial class NoteThing
{
public int Id { get; set; }
public int NoteId { get; set; }
public int ThingId { get; set; }
public Thing Thing { get; set; }
public Note Note { get; set; }
}
As there seems to be no nice way to handle this at the database level, I've found it best to handle this at the application level using the concrete type database schema, to produce dynamic joins.
Example in Entity Framework Core:
public GenericEntityProvider
{
private readonly IEnumerable<IEntityProvider> _entityProviders;
private readonly DatabaseContext _context;
public GenericEntityProvider(IEnumerable<IEntityProvider> entityProviders, DatabaseContext context)
{
_entityProviders = entityProviders;
_context = context;
}
public IEnumerable<Note> Get(Type type, int id) {
var provider = _entityProviders.GetPredicate(type, id);
return _context.Notes.Where(provider);
}
}
public CarNoteProvider : IEntityProvider
{
public Expression<Func<Note, bool>> GetPredicate(Type type, int id)
{
return x => x.CarNote.Any(cn => cn.CarId == id);
}
}

.net Core Many to Many relationship

I am trying to determine what would be the smartest way to accomplish this. I may be way way overthinking what I am trying to do, but here goes.
I have the following entities, simplified
public class Meet
{
public int Id { get; set; }
//various properties
public List<MeetComp> Competitors { get; set; }
}
public class Competitor
{
public int Id { get; set; }
// various properties
public List<MeetComp> Meets { get; set; }
[ForeignKey("GymManager")]
public int GymManagerId { get; set; }
public GymManager GymManager { get; set; }
}
public class GymManager
{
public int Id { get; set; }
//various properties
public List<Competitor> Competitors { get; set; }
}
public class MeetComp
{
public int Id { get; set; }
[ForeignKey("Competitor")]
public int CompetitorId { get; set; }
public Competitor Competitor { get; set; }
[ForeignKey("Meet")]
public int MeetId { get; set; }
public Meet Meet { get; set; }
}
So I am creating a razor page where I get a specific Gymmanager and load all the related competitors to display in a list, which I have working just fine.
However I need another list (on the same page) of the related competitors of the Gymmanager but also who have an entry in the "MeetComp" table by a specific meetid. So List #1 is all of my Competitors and List #2 is all of my Comptetitors that are registered for that Meet.
Would it be smarter to have EF pull the data I get the data the first time with a ThenInclude()? Then I write some logic to determine if they get added to list #2? or should I make another trip to the Database? Then if I do make another trip to the database is there an easy to way to query for the List of CompId's I already have?
So here's what I ended up doing is making another trip to the DB.
public async Task<IActionResult> GetRegisteredComps(List<int> Comps, int meetid)
{
if(Comps.Count == 0)
{
return Ok();
}
if(meetid == 0)
{
return BadRequest();
}
var query = _context.MeetsComps.Include(c => c.Competitor)
.AsQueryable();
query = query.Where(c => c.MeetId == meetid);
query = query.Where(c => Comps.Contains(c.CompetitorId));
var results = await query.ToListAsync();
return Ok(results);
}

How to bind custom model class in mvc

I am new in MVC. I am working on a project where i have created a model class and also context class which is working good if i view the record in normal view.
but if i try to get the data in group by "Series_Name" and bind it into same model class it gives error. here is my code
Here is Model class and DBContextClass
[Table("tblvideo")]
public class TVSerial
{
[Key]
public Int64 Video_ID { get; set; }
public string Series_Name { get; set; }
public string Season_No { get; set; }
public string Episode_No { get; set; }
public string Episode_Name { get; set; }
public string Time_Duration { get; set; }
public string File_Url_480p { get; set; }
public string File_Url_720p { get; set; }
public string Description { get; set; }
public bool Is_Active { get; set; }
public string Image_Url_Small { get; set; }
public string Image_Url_Big { get; set; }
}
public class TvSerialContext : DbContext
{
public DbSet<TVSerial> TvSerials { get; set; }
}
Here is controller class:
public class TvSerialController : Controller
{
public ActionResult ListAllTvSerial()
{
try
{
TvSerialContext tvContext = new TvSerialContext();
List<TVSerial> tv = tvContext.TvSerials.ToList();
return View(tv);
}
catch (Exception ex)
{
return Content(ex.Message);
}
}
}
Above code works as expected, but if i am doing this :
public ActionResult ListAllSeason(string serial)
{
try
{
TvSerialContext tvContext = new TvSerialContext();
List<TVSerial> tv = tvContext.TvSerials.Where(tvs => tvs.Series_Name == serial).Distinct().ToList();
return View(tv);
}
catch (Exception ex)
{
return Content(ex.Message);
}
}
it return all rows , i just want single row from every series_name and custom field "Series_Name,Season_No,Image_Url_Big"
i don't know how to achieve this.
getting result :
Expected result:-
You could do this by creating a view model and using a .GroupBy() clause
public class TVSerialVM
{
public string SeriesName { get; set; }
public string SeasonNo { get; set; }
public string ImageUrl { get; set; }
}
and the query to project into your view model
List<TVSerialVM> model = tvContext.TvSerials.Where(t => t.Series_Name == serial)
.GroupBy(t => new { t.Series_Name, t.Season_No, t.Image_Url_Big })
.Select(t => new TVSerialVM
{
SeriesName = t.Key.Series_Name,
SeasonNo = t.Key.Season_No,
ImageUrl = t.Key.Image_Url_Big
}).ToList();
Side note: Your duplicating data in the database (the season number and the image url). You should consider moving the image urls to another table with a relationship to the season number.
The reason you are getting multiple values even though you are using distinct is the Distinct method does not know what "equal" is for TVSerial.
You can use Distinct with IEqualityComparer.
https://msdn.microsoft.com/en-us/library/vstudio/bb338049(v=vs.100).aspx
Distinct is not guaranteed to on custom objects it doesn't know what to compare. I have used this SO in the past to make my custom object work with Distinct.
Creating a distinct list of custom type in C#

Can't correctly add associated objects into Entity Framework Context

I have and entity framework project exposed via a data service:
public class VersionContext : DbContext
{
public DbSet<VersionTreeEntry> VersionTreeEntries { get; set; }
public DbSet<PluginState> PluginStates { get; set; }
public static void SetForUpdates()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<VersionContext, Configuration>());
}
}
public class VersionTreeEntry
{
public VersionTreeEntry()
{
Children = new List<VersionTreeEntry>();
PluginStates = new List<PluginState>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public virtual ICollection<VersionTreeEntry> Children { get; set; }
public virtual ICollection<PluginState> PluginStates { get; set; }
public virtual VersionTreeEntry Ancestor { get; set; }
/// <summary>
/// Links to the ProtoBufDataItem Id for the session state.
/// </summary>
public int DataId { get; set; }
public string Notes { get; set; }
[Required]
public DateTime TimeStamp { get; set; }
[MinLength(1, ErrorMessage = "Tag cannot have a zero length")]
[MaxLength(20, ErrorMessage = "A tag name cannot contain over 20 characters")]
public string Tag { get; set; }
public bool IsUiNodeExpanded { get; set; }
[Required]
public string Version { get; set; }
[Required]
public string SessionName { get; set; }
}
public class PluginState
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public string PluginName { get; set; }
[Required]
public byte[] Data { get; set; }
}
As far as I can see, the data classes are defined correctly. I try to create some new objects and add them into the context, with their relations intact:
var session = new Session();
session.SessionName = "My new session";
VersionTreeEntry versionTreeEntry = new VersionTreeEntry();
versionTreeEntry.SessionName = session.SessionName;
versionTreeEntry.Version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
versionTreeEntry.TimeStamp = DateTime.Now;
_versionContext.AddToVersionTreeEntries(versionTreeEntry);
foreach (var plugin in session.Plugins)
{
using (var ms = new MemoryStream())
{
plugin.SaveState(ms);
PluginState state = new PluginState();
state.PluginName = plugin.PluginName;
state.Data = ms.ToArray();
versionTreeEntry.PluginStates.Add(state);
}
}
_versionContext.SaveChanges();
The problem is that the PluginState instances never actually get added to the database. If I add code to add them manually to the context, they do get added, but the foreign key pointing back to the VersionTreeEntry is null.
Again, this is a WCF DataService rather than vanilla EF, any idea what might be wrong?
Cheers
Posting the answer here from the comment section.
Agreed. The best way to do this is to call the following API:
_versionContext.AddRelatedObject(versionTreeEntry, "PluginStates", state);
Thanks
Pratik

CodeFirst - Update single property

We are using EF5, Code First approach to an MVC4 app that we're building. We are trying to update 1 property on an entity but keep getting errors. Here's what the class looks like which the context created:
public partial class Room
{
public Room()
{
this.Address = new HashSet<Address>();
}
public int RoomID { get; set; }
public Nullable<int> AddressID { get; set; }
public Nullable<int> ProductVersionID { get; set; }
public string PhoneNumber { get; set; }
public string AltPhone { get; set; }
public string RoomName { get; set; }
public string Description { get; set; }
public string Comments { get; set; }
public string Notes { get; set; }
public virtual ICollection<Address> Address { get; set; }
}
Here's our ViewModel for the view:
public class RoomDetailsViewModel
{
//public int RoomID { get; set; }
public string RoomName { get; set; }
public string PhoneNumber { get; set; }
public string AltPhone { get; set; }
public string Notes { get; set; }
public string StateCode { get; set; }
public string CountryName { get; set; }
public string ProductVersion { get; set; }
public int PVersionID { get; set; }
public List<SelectListItem> ProductVersions { get; set; }
public Room Room { get; set; }
}
Here's the Controller Action being called on "Save":
[HttpPost]
public virtual ActionResult UpdateRoom(RoomDetailsViewModel model)
{
var db = new DBContext();
bool b = ModelState.IsValid;
var rooms = db.Rooms;
var rm = rooms.Where(r => r.RoomID == model.Room.RoomID).Single();
//List<Address> address = db.Addresses.Where(a => a.AddressID == rm.AddressID).ToList<Address>();
rm.ProductVersionID = model.PVersionID;
//rm.Address = address;
db.Entry(rm).Property(r => r.ProductVersionID).IsModified = true;
//db.Entry(rm).State = System.Data.EntityState.Modified;
db.SaveChanges();
return View("RoomSaved", model);
}
All this view does is display data and allow the user to change the Product Version (from a SelectList), so, in the Room Entity, all we are updating is the ProductVersionID property, nothing else. We can get the data to display properly but when we click "save", we get this error:
An object of type 'System.Collections.Generic.List`1[[Models.Address,
Web.Mobile.TestSite, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null]]' cannot be set or removed from the Value
property of an EntityReference of type 'Models.Address'.
As you can see by the Controller Action, we've tried several different things but all seem to produce this error. I've tried to populate the model.Room.Address collection with an Address, without, but still get this error.
I read this StackOverflow article and this article as well but neither have solved my problem.
ANY help with this would be greatly appreciated!
After hours and hours of digging, turns out that EF did not import some of the PK's for my DB tables. What tipped me off to this was on the Room class, the PK RoomID did not have the [Key] attribute on it. I tried to reimport the table through the edmx but it never came through as a key (even though it's clearly marked PK in the DB). So, to get around it, I created a partial class of my DBContext and override the OnModelCreating event and included the key, like so:
public partial class DBContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Models.Room>().HasEntitySetName("Rooms");
modelBuilder.Entity<Models.Room>().HasKey(r => r.RoomID);
}
}
Once this was done, the Action saved the record as hoped.
I hope this helps someone else!