Using provider pattern with database in flutter - flutter-provider

I am new to flutter and especially provider pattern. I went through the documentation, examples and some tutorials for the provider pattern statemanagement and i am trying to implement it in one of my projects. I am developing a personal expenses manager app. The problem is that all the documentation, examples and tutorials assume the model provider has all the required data available in memory, that is, all the mock data is already there in a list. It is fairly easy to understand the addition/deletion of data and the change notification. But in a real app, the data needs to be loaded either from the local database or from the Internet. That is when things gets confusing and messy. Here is my model:
class Expense {
int id;
String name;
DateTime date;
double amount;
PaymentType paymentType; //This is an enum (card, cash etc.)
ExpenseCategory category; //Categories like fuel, groceries etc.
Expense({#required this.name, #required this.date, #required this.amount, #required this.paymentType, #required this.category});
}
class ExpenseCategory {
int id;
String name;
ExpenseCategory({#required this.name});
}
Data manipulation class:
class ExpenseRepository {
static Future<List<Expense>> getAllExpenses({#required int month}) async {
return await mockService.getAllExpensesData(month: month);
}
static Future<List<Expense>> getRecentExpenses() async {
return await mockService.getRecentExpensesData();
}
static Future<List<CategorywiseAmount>> getCategorywiseExpensesList({#required int month}) async {
return await mockService.getCategorywiseExpensesListData(month: month);
}
}
The data is, for the time being, loaded from a mock service which will be replaced by the local database. Nevertheless, it simulates the async/await pattern.
Keeping the above code in view, i have the following questions:
Do i have to convert the "Expense" model into a provider ("Expense" and "Expenses" provider) or do i have to create a separate class which will act as a provider? In the docs and tutorials, i have seen that the models have been converted to providers but is that the right thing to do? I may be wrong but i think the separation of concerns will be violated. As far as i have read, a model should not do anything else other than being a model.
How does the expense provider actually load data from the database (or from the mock database in my case)? If i follow the tutorials, i have to have a provider like this:
class ExpensesProvider with ChangeNotifier {
List<Expense> _expensesList;
List<Expense> get recentExpenses {
return _expensesList;
}
}
But how will the provider load data from mock database into the _expensesList property because the mock method getRecentExpenses() returns a future (and the real one will too) and that can't be used in the getter. Or do i have to return a future from the getter itself too?
If a new expense is added, the list of recent expenses should update automatically. Let's assume for the time being this provider is somehow hooked to the database. I have the following doubts:
a) Does the provider watch for the changes in the database or does it watch for changes in the in-memory model/list and trigger the rebuilds automatically?
b) Or maybe it doesn't watch any of above and we need to manually trigger it with notifyListeners?
The confusion comes from the comments
// Consumer looks for an ancestor Provider widget
// and retrieves its model (Counter, in this case).
// Then it uses that model to build widgets, and will trigger
// rebuilds if the model is updated.
These comments are from the flutter samples app https://github.com/flutter/samples/blob/master/provider_counter/lib/main.dart
Am i even using the right tools? I mean maybe there is something else which can be used instead of provider (but with similar or more feature) for use with local/database to make the process simpler.

Related

EF Core Update with List

To make updates to a record of SQL Server using Entity Framework Core, I query the record I need to update, make changes to the object and then call .SaveChanges(). This works nice and clean.
For example:
var emp = _context.Employee.FirstOrDefault(item => item.IdEmployee == Data.IdEmployee);
emp.IdPosition = Data.IdPosition;
await _context.SaveChangesAsync();
But is there a standard method if I want to update multiple records?
My first approach was using a list passing it to the controller, but then I would need to go through that list and save changes every time, never really finished this option as I regarded it as not optimal.
For now what I do is instead of passing a list to the controller, I pass each object to the controller using a for. (kind of the same...)
for(int i = 0; i < ObjectList.Count; i ++)
{
/* Some code */
var httpResponseObject = await MyRepositories.Post<Object>(url+"/Controller", Object);
}
And then do the same thing on the controller as before, when updating only one record, for each of the records...
I don't feel this is the best possible approach, but I haven't found another way, yet.
What would be the optimal way of doing this?
Your question has nothing to do with Blazor... However, I'm not sure I understand what is the issue. When you call the SaveChangesAsync method, all changes in your context are committed to the database. You don't have to pass one object at a time...You can pass a list of objects
Hope this helps...
Updating records in bulk using Entity Framework or other Object Relational Mapping (ORM) libraries is a common challenge because they will run an UPDATE command for every record. You could try using Entity Framework Plus, which is an extension to do bulk updates.
If updating multiple records with a single call is critical for you, I would recommend just writing a stored procedure and call if from your service. Entity Framework can also run direct queries and stored procedures.
It looks like the user makes some changes and then a save action needs to persist multiple records at the same time. You could trigger multiple AJAX calls—or, if you need, just one.
What I would do is create an endpoint—with an API controller and an action—that's specific to your needs. For example, to update the position of records in a table:
Controller:
/DataOrder
Action:
[HttpPut]
public async void Update([FromBody] DataChanges changes)
{
foreach(var change in changes)
{
var dbRecord = _context.Employees.Find(change.RecordId);
dbRecord.IdPosition = change.Position;
}
_context.SaveChanges();
}
public class DataChanges
{
public List<DataChange> Items {get;set;}
public DataChangesWrapper()
{
Items = new List<DataChange>();
}
}
public class DataChange
{
public int RecordId {get;set;}
public int Position {get;set;}
}
The foreach statement will execute an UPDATE for every record. If you want a single database call, however, you can write a SQL query or have a stored procedure in the database and pass the data as a DataTable parameter instead.

EF 5.0 Trouble updating entity which is already tracked

I'll preface this question with the following: I know there are a million posts on the internet about the old "An object with the same key already exists in the ObjectStateManager" issue. My scenario is a bit more complicated, I think.
I have a UnitOfWork class which creates a DbContext and passes it to any repository which is called. The pattern I'm using closely follows the Unit of Work tutorial on the ASP.NET site. Unlike the tutorial, my repositories take in Business entities, map them to data entities, and perform some CRUD action. My Business logic only works with Business entities. Here is what I'm trying to do in a sample Business Manager class:
_unitOfWork.Repository.Add(entity);
_unitOfWork.Save(); // context.SaveChanges() under the hood
...Perform some operations on the model...
_unitOfWork.Repository.Update(entity);
_unitOfWork.Save();
Here is a sample Update method from the repository:
public virtual void Update(entity)
{
var dataEntity = // map from business entity to data;
_context.Entry(dataEntity).State = EntityState.Modified;
}
It obviously fails on the last line. Here is where my confusion sets in:
The entity's State is Detached
When I attempt to change the State to Modified or Unchanged, it gives me the ObjectStateManager exception above.
When I attempt to detach the entity from the context (((IObjectContextAdapter)_context).ObjectContext.Detach(entity);) I get an exception about how the entity is not attached to the context, therefore, it cannot detach it. Very confusing (something fundamental I'm missing, for sure).
Many other posts suggest I make a database call, update that entity in the repository, then _unitOfWork.Save(). I don't like this approach. I shouldn't need to make an unnecessary network call to update an entity.
The Update method in the repository needs to handle two scenarios: 1) updating an entity which is not currently tracked by the context, and 2) updating an entity which IS currently tracked by the context. The second piece is what I'm struggling with.
Any help or insight is appreciated.
Thanks!
This means that there already is an object attached to the context with the same key as the new dataEntity. The existing object and the new entity both represent the same entry in the database but they are two different objects.
This may indicate that the lifespan of your _context is too long, but that's hard to judge from your code. It is certain though that the context was previously used to fetch an entity from the database that is subsequently duplicated by var dataEntity = ....
You may have to shorten the lifespan of the context, I can't tell. If you think it's OK you may want to use the Local collection to check whether the entity is already there. That will save the database round trip that Find may still make.
I found a hybrid solution which appears to work:
public virtual void Update(TB entity)
{
var dataEntity = Mapper.Map<TB, TD>(entity);
var pkey = _dbSet.Create().GetType().GetProperty("Id").GetValue(dataEntity);
var entry = _context.Entry(dataEntity);
if (entry.State == EntityState.Detached)
{
var attachedEntity = _dbSet.Find(pkey);
if (attachedEntity != null)
{
var attachedEntry = _context.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(dataEntity);
}
else
{
entry.State = EntityState.Modified;
}
}
else
{
entry.State = EntityState.Modified;
}
}

ASP.NET AJAX: How to limit amount of properties transfered to client

My web method returns object 'User' that has a lot of properties: Id, Nick, Email, FirstName, SecondName, etc...
[WebMethod]
public User GetUserById(int userId)
{
vfm_elita.elita_table.user.User user =
vfm_elita.elita_table.user.User.GetUserById(userId);
return user;
}
Is there any possibility to limit amount of properties returned? Or I should to create a separate class (UserForClientForParticular) that has only required properties?
Thanks.
P.S. Guess, my last idea will be the suggested answer :), but anyway, any thoughts are welcome
It's a good idea to use a data transfer object, specialized to expose only the properties that the client-side should know about. Alternatively, if you're prototyping, in a hurry, or don't want to create a DTO class for some other reason, you can use an anonymous type to pare down the response:
[WebMethod]
public object GetUserById(int userId)
{
vfm_elita.elita_table.user.User user =
vfm_elita.elita_table.user.User.GetUserById(userId);
// Will return something like {"Nick":"Encosia","FirstName":"Dave"}
return new { Nick = user.Nick, FirstName = user.FirstName };
}
You should always be very aware of what data you expose in your APIs, especially if there's a chance that they'll be consumed by external parties but even if they are only used internally. I would definitely recommend what you mentioned in your post and create a construct designed to expose only the data that is necessary in this context.
Update: also recommend taking a look at the AutoMapper project on codeplex that handles automatically mapping property values from one object (User) to another object (UserSummary).

Business object to multiple tables

I want to try custom code, this is for my uni project. What if I have Tables - UserCar, CarMake, and CarModel.
UserCar - userId, carId, carMakeId, CarModelId
CarMake - CarMakeId, MakeName
CarModel - CarModelId, ModelName
So I want to display on the page User car, using 3 layer architecture. So how do I map this tables??? to business object or objects??? Could you help me please?
Well, you mention 3-layer architecture, so I guess you're looking at a Data/Application/Presentation approach. Of course, in order for that to make sense you may need to provide more than the brief details you gave in your question.
For instance, when we talk about the Application tier, it really makes sense to have one if you have "Appalication logic". With your brief info there isn't really application logic other than displaying your data to screen. See this wikipedia entry for more info on the topic of Multitier (or n-tier) architecture (and 3-tiers as a subset) in general.
That being said, if you have your 3 tables in a data storage of sort (such as a database), we can quickly make a 3-tiers app like this.
1~ Data Tier:
Create classes that match the storage tables, such as (using C# syntax):
public class DT_UserCar
{
public string userId;
public string carId;
public string carMakeId;
public string CarModelId;
}
I'm using the DT_ prefix to indicate this class belongs to the Data Tier.
In addition, you need to have some code to let instance of these classes be read from the storage and probably be saved to storage. Of course you have options already. You could create a separate class that knows how to do all that, like
public class Storage
{
public DT_UserCar ReadUserCar(string carId) { /* implementation */ }
public DT_CarMake ReadCarMake(string carmakeId) { /* implementation */ }
/* and so on... */
}
Or you could decide that each class should know how to serialize/deserialize itself to/from the storage, and go with:
public class DT_UserCar
{
public string userId;
public string carId;
public string carMakeId;
public string CarModelId;
public static DT_UserCar Read(string carId) { /* implementation */ }
public void Write() { /* implementation */ }
}
A third, and much better alternative (for bigger projects) is to find a third-party tool that takes care of all of this for you. After all, given the storage structure (e.g.: the database schema) all of this code can be automated... I won't go into details here since you can find a lot of information about this sort of tools (ORM tools) and their characteristics, but mostly because it doesn't seem ot be part of your exercise.
2~ Application Tier:
As I said, your use case doesn't seem to include a lot of 'business logic'. However, you do mention that the data from those 3 storage tables should be merged somehow, so I'll take that as your one piece of business logic. Hence, we should create a business class (or business entity, or Domain Entity, or Domain model, whichever term you feel like using, they all have different connotations but a lot in common) like this:
public class AT_UserCar
{
public DT_UserCar _userCar;
public DT_CarMake _carMake;
public DT_CarModel _carModel;
public AT_UserCar(DT_UserCar userCar, DT_CarMake carMake, DT_CarModel carModel)
{
_userCar = userCar;
_carMake = carMake;
_carModel = carModel;
}
}
I'm using the AT_ prefix to indicate this class belongs to the Application Tier. Note that I would rather have those 3 as private properties, but for the sake of brevity I'm relaxing other guidelines in this sample code.
Now, as we read an instance of this class form the storage, we'll have to merge the proper DT_ objects in it. Again, you can have this code in the same class AT_UserCar, or decide to split it out into some separate class like this one:
public class AT_UserCarReader
{
public AT_UserCar Read(string userCarId, string carMakeId, string carModelId)
{
DT_UserCar userCar = DT_UserCar.read(userCarId);
DT_CarMake carMake = DT_CarMake.Read(carMakeId);
DT_CarModel carModel = DT_Carmodel.read(carModelId);
return new AT_UserCar(userCar, carMake, carModel);
}
}
An equivalent AT_UserCarWriter class would do the inverse operation of receiving a single AT_UserCar object and writing to the data storage 3 separate objects extracted from it: a DT_UserCar, a DT_CarMake, and a DT_CarModel.
Note that most of this code can also be automated and there is a plethora of tools that will take care of it for you.
3~ Presentation Tier:
Finally, we get to display something on screen. The important thing here is to remember that your Presentation Tier should never deal directly with the Data Tier, but only with the Application Tier.
So, for instance, if I have to retrieve a UserCar by id and display it in a web page, I could write something like this
AT_UserCar car = AT_UserCarReader.Read(userCarId, carMakeId, carModelId);
tbox_userId = car._userCar.userId;
That's, of course, a very small example, but I hope the quick run-through can help you out.
The core of 3-tier architecture (and n-tier, in general) is to separate different concerns into different layers. If you look at the example above, we targeted 3 concerns:
talking to the data storage: we did this exclusively in the Data Tier;
dealing with application logic such as 'merging' data from different tables into a single logical unit: we did this exclusively in the Application Tier;
dealing with presenting to screen the data and -in more general terms- interacting with the user: we did this exclusively in the Presentation Tier.
HTH.
Map the tables to Data Access Objects and use those in your Business Layer. Each one of your DAO will have properties corresponding to each column in the respective table; use any ORM of your liking (such as NHibernate) and you are good to go.

IRepository confusion on objects returned

I have some e-commerce code that I use often that uses Linq To SQL for saving orders to the database. I want to remove the tightly coupled Linq to SQL bit and pass in an IRepository instead but I am still a little confused on things.
Say I have a GetCustomer() method on my ICustomerRepository that returns a Customer object.
Do I need it to really return an ICustomer object that gets passed back from that method so if I switch from Linq To SQL to say SubSonic it's not a problem?
I believe I do, if that is the case is there a way in Linq To SQL to easily convert my Linq To SQL Customer object to my ICustomer object like SubSonics ExecuteSingle(Of ) method?
If you want your Customer class to be a plain object with no attachment to LINQ, then you will most likely need to write a mapper method to convert your LINQ-based Customer object to your plain Customer domain object. LINQ to SQL does not have such functionality built-in.
I have begun to wrap my mapping methods in an extension method for readability, and it really helps to keep the Repository code simple. For instance, an example CustomerRepository method my look like:
public Customer GetById(int id)
{
return dataContext.LINQCustomers.Where(c => c.Id == id)
.Single()
.ToDomainObject();
}
and the ToDomainObject() method is defined in an extension method like:
public static class ObjectMapper
{
public static Customer ToDomainObject(this Customer linqObject)
{
var domainObject = null
if (linqObject != null)
{
domainObject = new Customer
{
Id = linqObject.Id,
FirstName = linqObject.FirstName,
LastName = linqObject.LastName
}
}
return domainObject;
}
}
or something similar. You can do the same to convert your domain object back to a LINQ object to pass back into your repository for persistence.
You can have it return a Customer as long as Customer is a plain old .NET object, and not some db-generated entity. Your Customer domain object should have no knowledge about how (or if) it might be persisted to a database, and this is what should be returned from your repository. In your repository you might have some mapping code - this is quite common - that maps from [however you get the data back from its storage location] to your domain object. If you're using Linq-to-sql then this mapping would be from the Linq-To-Sql generated Customer table (and perhaps other tables - your Customer domain object likely won't map 1:1 to a particular table in the database) to your Customer domain object, which would live in a different namespace (and most likely, assembly).
There is no need to make it an ICustomer at all. A repository acts in a way as to make it look as though your persistent instances are in memory.
public interface ICustomerRepository
{
Customer GetByID(int id);
IEnumerable<Customer> GetByName(string name);
Customer GetByVatCode(string vatCode);
}
Some people would additionally include methods such as
void Add(Customer newCustomer);
void Delete(Customer deleted);
void Update(Customer modified);
The latter method implementations would most likely just update a unit of work.
The concept though is that these are just common ways of asking for Customer instances, the repository acts as a way of asking for them without defining how to ask for them.

Resources