Unable to get Item from SQLite.Net Async PCL - xamarin

I am struggling to get an Item by ID using the asynchronous API of SQLite.Net Async PCL. Here is my model class
public class Invoice : IEntityBase
{
public Invoice()
{
LineItems = new List<LineItem>();
DateCreated = DateTime.Now;
}
[PrimaryKey, AutoIncrement, Column("_id")]
public int Id { get; set; }
public DateTime DateCreated { get; set; }
public int Term { get; set; }
public bool Paid { get; set; }
public decimal Total { get; set; }
public string Notes { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<LineItem> LineItems { get; set; }
}
And the LineItems that has a One to Many relationship here
[PrimaryKey, AutoIncrement, Column("_id")]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
public int Qty { get; set; }
[ForeignKey(typeof(Invoice))]
public int InvoiceId { get; set; }
[ManyToOne]
public Invoice Invoice { get; set; }
Here is the constructor:
public SQLiteAsyncConnection DbConnection;
public InvoiceDatabase(ISQLitePlatform platform, string databasePath)
{
if (DbConnection == null)
{
var connectionAsync = new Func<SQLiteConnectionWithLock>(() =>
new SQLiteConnectionWithLock
(
platform,
new SQLiteConnectionString(databasePath, false)
)
);
DbConnection = new SQLiteAsyncConnection(connectionAsync);
DbConnection.CreateTableAsync<Invoice>();
DbConnection.CreateTableAsync<LineItem>();
}
}
Other CRUD methods (Insert, GetALL) is working except getting an Invoice by ID, and both Visual Studio and Xamarin Studio are not giving me any useful stacktrace.
Here is the Get Method
private readonly InvoiceDatabase _database;
public InvoiceRepository(ISQLitePlatform platform, string databasePath)
{
if (_database == null)
{
_database = new InvoiceDatabase(platform, databasePath);
}
}
public async Task<Invoice> GetInvoice(int id)
{
var result = await _database.DbConnection.Table<Invoice>()
.Where(t => t.Id == id)
.FirstOrDefaultAsync();
return result;
}
I am passing in the Android implementation of SQLite, and like I said the Database is created but I am unable to get the Invoice object back, I even tried
public Task<Invoice> GetInvoiceWithChildren(int id)
{
return _database.DbConnection.GetWithChildrenAsync<Invoice>(id);
}
Any Help will be greatly appreciated.

After three days of chasing shadows it turned out that it is just a very simple thing that is tripping me up. I am tying to save a List of objects like so
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<LineItem> LineItems { get; set; }
I missed the part of the documentation that repeats the fact that SQLite.Net is a lightweight ORM - that point could not be stressed enough so you will have to remove your full size ORM hats such EF. So after reading from the SQLite-Net Extension documentation which says
Text blobbed properties
Text-blobbed properties are serialized into a text property when saved and deserialized when loaded. This allows storing simple objects in the same table in a single column.
Text-blobbed properties have a small overhead of serializing and deserializing the objects and some limitations, but are the best way to store simple objects like List or Dictionary of basic types or simple relationships.
I change my proptery like so and everything is now working as expected. Off now to dealing with the nuances of Async and Await
[TextBlob("LineItemBlobbed")]
public List<LineItem> LineItems { get; set; }
public string LineItemBlobbed { get; set; }

Related

Creating an object with other object properties from DbContext in MVC EF Core

I am sorry if the answer to this question is so obvious, but all (and I really mean all) of my Google search results are purple, regardless of the search phrase I try to wrap around my question.
I am trying to build an MVC .NET Core 3.0 application with Code-First.
I am able to create my models, have these setup correct (I think) in my Database (Azure SQL), and using Visual Studio's standard templates to create controllers and views. I am therefore able to create each one of my model individually.
What I am trying to do is
Create a view from where I can create a Rental-object, with link to RentalOwner and ParkingSpot.
(Create a view from where I can see all rentals created. This is not in scope for this question)
My models
public class ParkingSpot
{
public int ParkingSpotId { get; set; }
public int ParkingSpotNumber { get; set; }
}
public class RentalOwner
{
public int RentalOwnerId { get; set; }
public int TenantId { get; set; }
public Tenant Tenant { get; set; }
}
public class Tenant
{
public int TenantId { get; set; }
[Required]
[Display(Name="Navn")]
public string Name { get; set; }
[EmailAddress]
[Required]
public string Email { get; set; }
}
public class Rental
{
public int RentalId { get; set; }
public int ParkingSpotId { get; set; }
public ParkingSpot ParkingSpot { get; set; }
public int RentalOwnerId { get; set; }
public RentalOwner RentalOwner { get; set; }
}
I have tried creating a ViewModel, to use for creation of the Rental-model and the binding to other models.
public class RentalCreationView
{
public int Id { get; set; }
public Rental Rental { get; set; }
public int ParkingSpotId { get; set; }
public int TenantId { get; set; }
}
I've tried with this GET and HttpPost POST Actions in my Controller.
// GET: Rentals/Create
public async Task<IActionResult> CreateAsync()
{
var parkingSpots = await _context.ParkingSpots.ToListAsync();
ViewData["ParkingSpots"] = new SelectList(parkingSpots, "ParkingSpotId", "ParkingSpotNumber");
var tenants = await _context.Tenants.ToListAsync();
ViewData["Tenants"] = new SelectList(tenants, "TenantId", "Name");
return View();
}
public async Task<IActionResult> Create(RentalCreationView rcw)
{
if (ModelState.IsValid)
{
_context.RentalOwners.Add(rcw.Rental.RentalOwner);
_context.Rentals.Add(rcw.Rental);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(rcw);
}
I don't think my issue is with my View, and I guess I am missing something in either my models or in my controller.
Right now, when I try to create a Rental, the view is just loading for a couple of minutes after submit.
I have seen numerous of tutorials, read hundreds of questions and articles, and I know that I am missing some basic steps, but the code above is what I have right now (I have about 500 lines of commented out code that doesn't work).
I've spent 2 weeks trying to learn how to do this but I need some help from someone who knows what I'm trying to do.
Any relevant links, videos or documentation would be awesome.. I am really stuck deep.
Thank you
EDIT: I have found a solution, and to all future readers who got this page from their 1000th Google search, what I did was change a bit in the models and add this HttpPost Create in my Controller.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(RentalCreationView rcw)
{
List<ParkingSpot> parkingSpots = _context.ParkingSpots.ToList();
List<Tenant> tenants = _context.Tenants.ToList();
RentalOwner ro = new RentalOwner
{
Tenant = tenants.Find(t => t.TenantId == rcw.TenantId),
OwnerSince = rcw.StartDate
};
Rental ren = new Rental
{
StartDate = rcw.StartDate,
ParkingSpot = parkingSpots.Find(ps => ps.ParkingSpotId == rcw.ParkingSpotId),
RentalOwner = ro
};
if (ModelState.IsValid)
{
_context.RentalOwners.Add(ro);
_context.Rentals.Add(ren);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
else
{
var errors = ModelState.Select(x => x.Value.Errors)
.Where(y => y.Count > 0)
.ToList();
}
return View();
}

Updating one of the related entity

I'm developing bulletin board system (as part of my training of asp.net mvc). I have a basic understanding of data modeling, but I have a doubt the way I've created my model. The core logic is to post ad with the following categories realty, auto and service. Initially I tried to use TPH approach, but then faced with problem of binding my models and automapper configuration. Now I think to use zero or one relationship.
I have a Ad model:
public class Ad
{
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public virtual Realty Realty { get; set; }
public virtual Auto Auto { get; set; }
public virtual Service Service { get; set; }
}
Realty:
public class Realty
{
[Key]
[ForeignKey("Ad")]
public int AdID { get; set; }
public string Type { get; set; }
public string NumberOfRooms { get; set; }
public virtual Ad Ad { get; set; }
}
Auto and service models have the same foreign key as the Realty model.
My db context:
public DbSet<Ad> Ads { get; set; }
public DbSet<Realty> Realties { get; set; }
public DbSet<Auto> Autos { get; set; }
public DbSet<Service> Services { get; set; }
I need update Ad model with one related model only. I'm using scaffolded controller action, which includes all related models:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Include = "Title,Descirpiton,Realty,Auto,Service")] Ad ad)
{
if (ModelState.IsValid)
{
db.Ads.Add(ad);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewBag.ID = new SelectList(db.Autos, "AdID", "CarType", ad.ID);
ViewBag.ID = new SelectList(db.Realties, "AdID", "Type", ad.ID);
ViewBag.ID = new SelectList(db.Services, "AdID", "ServiceType", ad.ID);
return View(ad);
}
The problem, that it makes possible to post Ad with all related models together. Before diving deep I wanted to ensure that I'm on a right way of doing this.
Thanks.
You're close. Based on what it looks like you're trying to do you should be using a table-per-type model. You create the base (Ad) and then inherit from it to create the sub-types.
public class Ad
{
[Key]
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
}
[Table("Realty")]
public class Realty : Ad
{
public string Type { get; set; }
public string NumberOfRooms { get; set; }
}
Your context remains the same. You can now create the appropriate sub-type when you know what kind of ad is being created.
var ad = new Realty();
ad.Title = "...";
ad.Description = "...";
ad.Type = "...";
ad.NumberOfRooms = "...";
You can retrieve specific ad types by using the specific type on the context.
db.Realty.ToList();
Or you can retrieve all the ads and interrogate the types as you loop over them.
var ads = db.Ads.ToList();
foreach(var ad in ads)
{
if(ad is Realty)
// do Realty stuff
else if (ad is Auto)
// do Auto stuff
}

How do I write the Linq query to get complex model items?

I'm using EF Code First. Now, I'm having a hard time figuring out how to write the LINQ to retrieve the data into my models in my Controller, to display them in a view. Basically, I am receiving a feed of HolterTest data, and I am trying to create a worklist for the people who do a bunch of specific tasks to process the HolterTest, allowing them to flag the tasks as they are completed, and provide status of where the individual tests are in the process The basic Task class is so they can add or alter steps in the process, with the displayOrder being the order in which tasks are done. A WorkTask is a specific instance of a task, allowing us to mark who completed it, and when. A WorkItem is the complex type that includes the HolterTest, the list of WorkTasks, and status information, including when the WorkTasks were all completed.
Model Classes:
public class HolterTest
{
public Int32 HolterTestID { get; set; }
public string PatientNumber { get; set; }
public string LastName { get; set; }
public DateTime RecordingStartDateTime { get; set; }
public System.Nullable<DateTime> AppointmentDateTime { get; set; }
}
public class Task
{
public Int32 TaskID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Int32 DisplayOrder { get; set; }
public bool IsActive { get; set; }
}
public class WorkTask
{
public Int32 WorkTaskID { get; set; }
public Task Task { get; set; }
public bool IsCompleted { get; set; }
public System.Nullable<DateTime> CompletedDateTime { get; set; }
public string CompletedBy { get; set; }
}
public class WorkItem
{
public Int32 WorkItemID { get; set; }
public HolterTest HolterTest { get; set; }
public string Status { get; set; }
public List<WorkTask> WorkTasks { get; set; }
public bool IsStarted { get; set; }
public bool IsCompleted { get; set; }
public System.Nullable<DateTime> CompletedDateTime { get; set; }
}
Currently I have a business logic function that takes the list of HolterTests, finds the ones that don't have a WorkItem, and creates the WorkItems, associates the HolterTests including the WorkTasks, based on the current active list of Tasks.
My problem is how to write the LINQ to get all of the WorkItems (with their child items) for my WorkItemController so I can display the work to do in a View (WorkItems where IsCompleted = false) by PatientNumber, and make it possible to update WorkTasks for a particular WorkItem.
You want to access the related using it's navigation properties. Note that in your example, you haven't setup the navigation properties to be virtual. You should should update your model like this:
public class WorkItem
{
public Int32 WorkItemID { get; set; }
public virtual HolterTest HolterTest { get; set; }
public string Status { get; set; }
public virtual List<WorkTask> WorkTasks { get; set; }
public bool IsStarted { get; set; }
public bool IsCompleted { get; set; }
public System.Nullable<DateTime> CompletedDateTime { get; set; }
}
A simple function for accessing the work items by patient number is this:
IEnumerable<WorkItem> GetWorkIncompleteWorkItemsByPatient(string patientNumber)
{
var db = new YourContext();
return db.WorkItems.Where(wi => wi.IsCompleted == false && wi.HolterTest.PatientNumber == patientNumber);
}
Then to work on the related tasks, you would access it through the task, in this example if you knew the task ID:
var workTask = YourWorkItem.WorkTasks.FirstOrDefault(wt => wt.WorkTaskID == worktaskId);
You could look through all the tasks in the work item like this:
foreach (var workTask in YourWorkItem.WorkTasks)
{
//your logic here...
}
Linq to entities explained
http://msdn.microsoft.com/en-us/library/bb399367.aspx
But starting here may suit better: The EF Main Site http://msdn.microsoft.com/en-us/data/ee712907
if you really want to dive straight intry this video and sample code. http://msdn.microsoft.com/en-us/data/jj193542
then see this http://msdn.microsoft.com/en-us/data/jj573936
Essentially based on the POCO you have you could read per POCO and get the data that way.
However EF does a lot of heavy lifting if the POCOS have navigational properties and foreign keys defined. Worth revisiting the POCO definitions and Code-First patterns.

EF Code First and linq extension methods - foreign keys, am i doing it wrong?

I have something like this: (pseudocode)
public class Author
{
int id;
public List<Thread> Threads;
public List<ThreadPoints> ThreadPointses;
}
public class Thread
{
int id;
public List<ThreadPoints> ThreadPointses;
}
public class ThreadPoints
{
int id;
int Points;
}
And i am not sure if above is correct, but now i would want to obtain number of points' that specified Author have in specified Thread.
I cannot directly call ThreadPoints.Thread_id, because it's not accessible, even if it physically is in the database.
So do i need to change my model, or am i unaware of some useful methods?
So basically, my model looks like that:
public class Account
{
[Key]
public Guid AccountId { get; set; }
public string UserName { get; set; }
public List<Post> Posts { get; set; }
public List<Post> ModifiedPosts { get; set; }
public List<Thread> Threads { get; set; }
public List<ThreadPoints> ThreadPointses { get; set; }
public List<Thread> LastReplied { get; set; }
public int Points { get; set; }
}
public class Thread
{
[Key]
public int Id { get; set; }
public List<ThreadPoints> ThreadPointses { get; set; }
public List<Post> Posts { get; set; }
public int CurrentValue { get; set; }
public int NumberOfPosts { get; set; }
public int TotalValue { get; set; }
public int Views { get; set; }
public string Title { get; set; }
public DateTime DateCreated { get; set; }
}
public class ThreadPoints
{
[Key]
public int Id { get; set; }
public int Points { get; set; }
}
And what i need, is, when user creates a thread, he gives some amount of points into it. In the next action, i want to take that amount of points (from database), and increase it. But i only have thread id as input information.
Your answer might be good, (as far i am trying to implement it), but anyways, i am not sure about this model. Maybe i should manually add foreign keys into my model? It surely would be simpler, but then i would have two foreign keys in my database...
Since you're not explicitly mapping your FK's, entity framework is generating them and hiding them away, so to get to the Id's of the properties, you'll need to follow the navigation collections.
I'm not sure about your question, but are you wanting the number of Points, inside of a specific Threadpoint for a given author? Your model doesn't seem to support this very well, but you could do something like this-
public int GetPoints(Author author, Thread thread)
{
int points = author.Threads.FirstOrDefault(t => t.id == thread.id).ThreadPointses.Sum(tp => tp.Points);
}
This would return the sum of all the points contained in the list of threadpoints, which are contained in the list of threads with the same id as the thread you passed in, for the specified author.
If this doesn't work for you - can you post your actual model?

asp.net mvc 3 entity framework, passing model info in Get request of create action

I'm having trouble passing view information from my Get/Create action to my view. Here are my three model classes;
public class Competition
{
public int Id { get; set; }
public int CompetitionId { get; set; }
public string Name { get; set; }
public string Prize { get; set; }
}
public class CompetitionEntry
{
public int Id { get; set; }
public int CompetitionEntryId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int CompetitionId { get; set; }
}
public class CompetitionEntryViewModel
{
public int Id { get; set; }
public Competition Competitions { get; set; }
public int CompetitionId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
Here is my Get/Create action in CompetitionEntry Controller;
public ActionResult Create(int id)
{
CompetitionEntryViewModel competitionentryviewmodel = db.CompetitionEntriesView.Find(id);
return View(competitionentryviewmodel);
}
I know this doesn't work. The id parameter goes into the URL fine. How to I get access to my Competition class in th Get action? I need to be able to show the competion name on my Create Competition entry view.
Thanks in advance!
public ActionResult Create(int id)
{
var data = db.CompetitionEntriesView.Find(id);
CompetitionEntryViewModel competitionentryviewmodel = new CompetitionEntryViewModel();
competitionentryviewmodel.CompetitionName = data.Name;
return View(competitionentryviewmodel);
}
What you are trying to do is build an object graph and display it through a view model. In order to do this, you need to map your domain model(s) to your view model.
You can do the mapping yourself by writing a lot of code (re-inventing the wheel), or, you could consider using third party tools to do this for you. I recommend you use an AutoMapper as it is very simple to use imo.
The other problem is that your view model contains a domain model. This is likely to cause you a lot of headache in near future. If I were you, I would replace Competition with CompetitionViewModel.
I would also consider creating a view model for a list of competitions, i.e. CompetitionsViewModel. Look into partial views to see how you can display a list of competitions.
Good luck

Resources