Giter Club home page Giter Club logo

urf.net's Introduction

URF.NET    NuGet Badge

Unit-of-Work & Repository Framework | Official URF, Trackable Entities & Design Factory Team

Docs: goo.gl/6zh9zp | Subscribe URF Updates: @lelong37 | NuGet: goo.gl/WEn7Jm

This framework (over 100K+ total downloads) minimizes the surface area of your ORM technology from disseminating in your application. This framework was deliberately designed to be lightweight, small in footprint size, and non-intimidating to extend and maintain. When we say lightweight we really mean lightweight, when using this framework with the Entity Framework provider there are only 10 classes. This lightweight framework will allow you to elegantly, unobtrusively, and easily patternize your applications and systems with Repository, Unit of Work, and Domain Driven Design. To use Generic Repositories or not? The framework allows the freedom of both, generic repositories and the ability to add in your own domain specific repository methods, in short Unit of Work with extensible and generic Repositories.

Live demo: longle.azurewebsites.net

Architecture Overview (Sample Northwind Application with URF Framework)

Architecture Overview (Sample Northwind Application & Framework)

URF sample and usage in ASP.NET Web API

public class CustomerController : ODataController
{
    private readonly ICustomerService _customerService;
    private readonly IUnitOfWorkAsync _unitOfWorkAsync;

    public CustomerController(
        IUnitOfWorkAsync unitOfWorkAsync,
        ICustomerService customerService)
    {
        _unitOfWorkAsync = unitOfWorkAsync;
        _customerService = customerService;
    }

    // GET: odata/Customers
    [HttpGet]
    [Queryable]
    public IQueryable<Customer> GetCustomer()
    {
        return _customerService.Queryable();
    }

    // GET: odata/Customers(5)
    [Queryable]
    public SingleResult<Customer> GetCustomer([FromODataUri] string key)
    {
        return SingleResult.Create(_customerService.Queryable().Where(t => t.CustomerID == key));
    }

    // PUT: odata/Customers(5)
    public async Task<IHttpActionResult> Put(string key, Customer customer)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (key != customer.CustomerID)
        {
            return BadRequest();
        }

        customer.TrackingState = TrackingState.Modified;
        _customerService.Update(customer);

        try
        {
            await _unitOfWorkAsync.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!CustomerExists(key))
            {
                return NotFound();
            }
            throw;
        }

        return Updated(customer);
    }

    // POST: odata/Customers
    public async Task<IHttpActionResult> Post(Customer customer)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        customer.TrackingState = TrackingState.Added;
        _customerService.Insert(customer);

        try
        {
            await _unitOfWorkAsync.SaveChangesAsync();
        }
        catch (DbUpdateException)
        {
            if (CustomerExists(customer.CustomerID))
            {
                return Conflict();
            }
            throw;
        }

        return Created(customer);
    }

    //// PATCH: odata/Customers(5)
    [AcceptVerbs("PATCH", "MERGE")]
    public async Task<IHttpActionResult> Patch([FromODataUri] string key, Delta<Customer> patch)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        Customer customer = await _customerService.FindAsync(key);

        if (customer == null)
        {
            return NotFound();
        }

        patch.Patch(customer);
        customer.TrackingState = TrackingState.Modified;

        try
        {
            await _unitOfWorkAsync.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!CustomerExists(key))
            {
                return NotFound();
            }
            throw;
        }

        return Updated(customer);
    }

    // DELETE: odata/Customers(5)
    public async Task<IHttpActionResult> Delete(string key)
    {
        Customer customer = await _customerService.FindAsync(key);

        if (customer == null)
        {
            return NotFound();
        }

        customer.TrackingState = TrackingState.Deleted;

        _customerService.Delete(customer);
        await _unitOfWorkAsync.SaveChangesAsync();

        return StatusCode(HttpStatusCode.NoContent);
    }

    // GET: odata/Customers(5)/CustomerDemographics
    [Queryable]
    public IQueryable<CustomerDemographic> GetCustomerDemographics([FromODataUri] string key)
    {
        return
            _customerService.Queryable()
                .Where(m => m.CustomerID == key)
                .SelectMany(m => m.CustomerDemographics);
    }

    // GET: odata/Customers(5)/Orders
    [Queryable]
    public IQueryable<Order> GetOrders([FromODataUri] string key)
    {
        return _customerService.Queryable().Where(m => m.CustomerID == key).SelectMany(m => m.Orders);
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _unitOfWorkAsync.Dispose();
        }
        base.Dispose(disposing);
    }

    private bool CustomerExists(string key)
    {
        return _customerService.Query(e => e.CustomerID == key).Select().Any();
    }
}

Implementing Domain Logic with URF Service Pattern

All methods that are exposed from Repository<TEntity> in Service<TEntity> are overridable to add any pre or post domain/business logic. Domain business logic should be in the Service layer and not in Controllers or Repositories for separation of concerns.

  1. Create an Interface e.g. ICustomerService, which should always inherit IService<TEnttiy> e.g. IService<Customer>
  2. Implement the concrete implementation for your Interface e.g. CustomerService which implements ICustomerService
  3. If using DI & IoC, don't forget to wire up the binding of your Interface and Implementation e.g. container.RegisterType<ICustomerService, CustomerService>(), see next example for more details on wiring up DI & IoC.
public interface ICustomerService : IService<Customer>
{
    decimal CustomerOrderTotalByYear(string customerId, int year);
    IEnumerable<Customer> CustomersByCompany(string companyName);
    IEnumerable<CustomerOrder> GetCustomerOrder(string country);
}


public class CustomerService : Service<Customer>, ICustomerService
{
    private readonly IRepositoryAsync<Customer> _repository;

    public CustomerService(IRepositoryAsync<Customer> repository) : base(repository)
    {
        _repository = repository;
    }

    public decimal CustomerOrderTotalByYear(string customerId, int year)
    {
        // add any domain logic here
        return _repository.GetCustomerOrderTotalByYear(customerId, year);
    }

    public IEnumerable<Customer> CustomersByCompany(string companyName)
    {
        // add any domain logic here
        return _repository.CustomersByCompany(companyName);
    }

    public IEnumerable<CustomerOrder> GetCustomerOrder(string country)
    {
        // add any domain logic here
        return _repository.GetCustomerOrder(country);
    }

    public override void Insert(Customer entity)
    {
        // e.g. add any business logic here before inserting
        base.Insert(entity);
    }

    public override void Delete(object id)
    {
        // e.g. add business logic here before deleting
        base.Delete(id);
    }
}

URF Sample DI & IoC Configuration with Framework of your choice, exampled here using Microsoft Unity DI & IoC

UnityConfig.cs

public class UnityConfig
{
    private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
    {
        var container = new UnityContainer();
        RegisterTypes(container);
        return container;
    });

    public static IUnityContainer GetConfiguredContainer()
    {
        return container.Value;
    }

    public static void RegisterTypes(IUnityContainer container)
    {
        container
            // Register DbContext instead of IDataDataContext, which is now obsolete.
            //.RegisterType<IDataContextAsync, NorthwindContext>(new PerRequestLifetimeManager())
            .RegisterType<DbContext, NorthwindContext>(new PerRequestLifetimeManager())
            .RegisterType<IUnitOfWorkAsync, UnitOfWork>(new PerRequestLifetimeManager())
            .RegisterType<IRepositoryAsync<Customer>, Repository<Customer>>()
            .RegisterType<IRepositoryAsync<Product>, Repository<Product>>()
            .RegisterType<IProductService, ProductService>()
            .RegisterType<ICustomerService, CustomerService>()
            .RegisterType<INorthwindStoredProcedures, NorthwindContext>(new PerRequestLifetimeManager())
            .RegisterType<IStoredProcedureService, StoredProcedureService>();
    }
}

Roadmap: URF .NET Core (alpha-release) ETA: February 2018

  • Intial URF .NET Core release will ship with default provider Entity Framework Core, as mentioned, overtime we'll bring on more providers.
  • First and foremost, learning from current .NET URF through comments, suggestions, real world feedback from enterprise level teams, URF team's actual experiences working with other teams/projects as a guidance practice to improve while implementing new URF .NET Core version. This list is quite the list, far to much to list here, however we'll include and generate a list specific to each of our releases moving forward in URF .NET Core versions.
  • Easily implement customizations e.g. adding audit trails with adding a simple abstraction such as IAuditable to our Entity.cs base class for your Entities.
  • Quickly get up and running with URF under a minute, we've recently just started publishing URF to NuGet, we're already approaching 1000 downloads. Shipping URF as NuGet packages is definitely something we did not realize as an added value. We were mistaken that most teams would like to clone/fork and include URF projects directly in their solution for infinite customizations possibilities however this was actually not the case. In reality, most teams use URF as is, right out the box, with zero customizations.
  • Although we'll be shipping URF as NuGet packages, new .NET Core version we'll have a lazer focus on modularity. Meaning we will several URF pacakges to further open opportunities such as creating other providers for URF other than Entity Framework Core e.g. NHibernate, MongoDB, DocumentDb, Cosmos, etc...
  • Tooling, tooling, tooling. The new URF .NET Core version architeture and design will set the stage for tooling such as code generation with templating with .NET Handlbars and/or Razor. We are considering to have full parity across different runtimes .NET Core is able to run in e.g. Mac, Linux, Windows, etc. We will performing rigurous due-dilligence to ensure this (XPLAT).
  • URF .NET Core will be a completey seperate rewrite and entirely new product, will have deep throught in it's new arcitecture and design for microservices world e.g. Azure Functions, AWS Lambdas, etc...
  • URF Sample will be updated to Angular v5 and Kendo UI for Angular (Kendo UI for Angular is also a complete new product line, which is now built from the ground up with Angular vs. Kendo UI for AngularJS which was jQuery widgets wrapped with AngularJS directives)
  • URF Sample app will also demonstrate lastest versionf of OData running in ASP.NET Core Web API
  • Trackable Entities Team has already been included in current version of .NET URF, and will also be supported in .NET Core version. This is a very powerful feature, which allows Entites to self track their state (e.g. Added, Modified, Delete, None) without DbContext. This is extremely helful for tracking object graphs and maintaning all entity states in a complex object graph accross physical boundaries, again while doing so with zero dependency on DbContext and more importantly doing so with zero dependency on Entity Framework or any other data provider. We've already released Trackable Entities for TypeScript/Javascript as an NPM package, allowing teams to take advantage of self Tracking Entities not only across physical boundaries but across different runtimes as well. Most common usecase for this is SPA (Angular, ReactJS, Aurelia, Vue.js, etc...) while using Trackable Entities for TypeScript /Javascript and passing object graphs with their states to Web APIs using URF.
  • Many more improvements e.g. performance, fusioning on a few design patterns in URF's core e.g. striking the best compromise and balance between Visitor Pattern and Recursion when traversing any object graphs, and so much more and to many to list here, again, we'll include a list with every release in each versions release notes.

URF Features & Benefits

  • Repository Pattern - 100% extensible ready
  • Unit of Work Pattern - 100% atomic & transaction ready
  • Service Pattern - pattern for implementing business, domain specific logic with 100% separation of concerns e.g. ICustomerService, IOrderService
  • Minimize footprint of your ORM and data access layer
  • DI & IoC 100% ready
  • REST, Web API & OData 100% ready
  • 100% testable & mockable
  • 100% support for Stored Procedures
  • Repository Pattern supports IEnumerable and/or IQueryable
  • Trackable Entities - When using URF, entities are 100% automatically self tracking, states are automatically trackable (New, Updated, Deleted, Unchanged), allowing entity or complex object graph states to be trackable across physical boundaries and application layers. Entity state can be tracked in Angular all the way to Web API.
  • Full (Northwind) sample application (Angular, Web API, OData, Entity Framework, SQL)
  • 100% unit tests & integration tests - Integration tests, will drop and re-create NorthwindTest database everytime integration tests are ran

urf.net's People

Contributors

andyattib avatar davidrogersdev avatar ivanfarkas avatar lelong37 avatar reddy6ue avatar sandord avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

urf.net's Issues

Cosmos DB sql api

It looks like a logical next step to support cosmosdb sql api query and associated repositories.

.net core ODATA automatic filter AppId

How to add tenantId to your queries automatically with odata.


public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)
{
    return base.ApplyQuery(queryable, queryOptions);
}

[URF.Repository.Pattern.Ef6] Package dependency of CommonServiceLocator

I use the Urf package v5.1.0-beta but
If the package [CommonServiceLocator] is updated to the latest version [2.0.1], I get the following error :

exception:
System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Practices.ServiceLocation, Version=1.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.

The error is gone if I use the version [1.3.0.0] of CommonServiceLocator package.
If the version 1.3.0.0 must be used then it should be explicitely setted in the nuget dependency no ?

Pattern for approaching SoftDeletes

Would like to get some advice on how to approach Soft Deletes for our tables. If we assume that all tables in our Database have a IsDeleted bit. What would be the best approach for the following

  • Marking Related Entities for Delete

    • How do we grab the related entities in code similar to the entity Includes?
    • Currently having to do several Includes and Selects to traverse the tree is ugly and trying to avoid using linq query syntax over several joins as well.
  • Filter related Entities after delete once they are deleted

    • Is there a default filter we can apply when using a queryable() so all nested items are automatically filtered based on a specified column?

Convert from MS Test to XUnit

Converting from MS Test to XUnit for overall better .NET testing framework, API's as well as X-Plat compatibility e.g. running/compiling w/ Travis CI etc.

.NET Core/EF 3.0 - Owned Entity - Error on insert

I am unable to insert when there is one or more owned entities (no nested entities).
It's working with DBContext.
Using:

  • .NET Core SDK 3.0.100-preview3-010431
  • Microsoft.EntityFrameworkCore 3.0.0-preview3.19153.1

Exception:
The entity of type 'Entity' is sharing the table 'Entity' with entities of type 'Entity.OwnedEntity#OwnedEntity', but there is no entity of this type with the same key value '{Id: -2147482647}' that has been marked as 'Added'.

It's a known issue.
See: EF Core 2 Owned Entities and Temporary Work-Arounds
Would be nice to have a fix or at least a roadmap to fix this in the trackable entities.

Delete not working in sample project

Hey guys,

Amazing solution, really learning a lot as i go thru it. but I cant seem to get past the delete methods in the Service. In your sample repo, or in the live demo on azure.

Please advise.

Thanks again for sharing your expertise

--brian

Error with .net 4.5.2

Hi Mr Longle,

I used to use your framework in my project, but now when install URF.Repository framework, There is a issues with me:

Could not load file or assembly 'Urf.Repository.Pattern' or one of its dependencies. An attempt was made to load a program with an incorrect format.

Can you help me resolve it

Query().SelectPage() Method Error

Hi when i try to Query().SelecPage() its throw exception

System.NotSupportedException: The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'.

Also i thing QueryFluent and QueryObject not orm independent can you move them common project

Thank you

GroupBy support?

Perhaps I am simply missing something obvious, but I am unable to see a way to perform a simple GroupBy on these generic repositories that will occur at the SQL level. Is this functionality currently supported by the generic repositories created by URF.NET?

missing packages

hi mr lelong37,

Are you missing TrackableEntities.Common packages when get package from NuGet, when I got source code to build dll, I saw you use ITrackable instead of. If I get URF via Nuget, issues when run because URF missing dependency library. You can check again if I think wrong.

Thank you

issues with DeleteAsync

Hi lelong37,

I showed you missing Context.ApplyChanges(entity) in method Repository.DeleteAsync

public virtual async Task DeleteAsync(CancellationToken cancellationToken, params object[] keyValues)
{
var entity = await FindAsync(cancellationToken, keyValues);

        if (entity == null)
        {
            return false;
        }

        entity.TrackingState = TrackingState.Deleted;
        return true;
    }

Please fix to DeleteAsync

Thank you

DbTransaction Not Disposed

Applies to 4.2.
If a transaction is started with UnitOfWork, it is not explicitly closed in the Dispose method. The _transaction field in class UnitOfWork should be checked and disposed as needed.

Add LoadProperty method to IRepository, IRepositoryAsync

This will load a reference property.

IRepository:

void LoadProperty(TEntity item, Expression<Func<TEntity, object>> property);

IRepositoryAsync:

Task LoadProperty(TEntity item, Expression<Func<TEntity, object>> property);

Repository (.NET Core implementation -- will be different for EF 6.x):

public void LoadProperty(PlexApp item, Expression<Func<PlexApp, object>> property) => _context.Entry(item).Reference(property).Load();

public async Task LoadProperty(PlexApp item, Expression<Func<PlexApp, object>> property) => await _context.Entry(item).Reference(property).LoadAsync();

Keep getting System.BadImageFormatException when I upgraded to 4.2

I upgraded the old Repository.Pattern from 3.3.4 to Urf.Repository.Pattern 4.2 and I started getting the following exception

Could not load file or assembly 'Urf.Repository.Pattern, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An attempt was made to load a program with an incorrect format.

Exception thrown: 'System.BadImageFormatException' in mscorlib.dll
An exception of type 'System.BadImageFormatException' occurred in mscorlib.dll but was not handled in user code
Could not load file or assembly 'Urf.Repository.Pattern, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An attempt was made to load a program with an incorrect format.

Deadlock in UnitTest

Hi,

I'm running Unit Test and can't run all test cases due to deadlock in Repository Tests. Below is the screenshot of code casing deadlock.
capture
capture
capture
capture

Extension method must be defined in a non-generic static class

My service class wants to be static and I'm not sure what I'm doing wrong. The service class causes the compiler error:

Error CS1106 Extension method must be defined in a non-generic static class Northwind.Service D:\src\samples\URF.NET-master\URF.NET-master\main\Sample\Northwind.Service\DynamicMenuService.cs 11 Active

Repository Class

`using Northwind.Entities.Models;
using Repository.Pattern.Repositories;
using System.Collections.Generic;
using System.Linq;

namespace Northwind.Repository.Repositories
{
public static class DynamicMenuRepository
{
public static IEnumerable DynamicMenusByCategoryAndType(
this IRepositoryAsync repository, MenuCategory menuCategory, MenuType menuType)
{
return repository
.Queryable()
.Where(x => x.TypeId == menuType && x.MenuCategoryId == menuCategory)
.OrderBy(x => x.SortOrder)
.AsEnumerable();
}
}
}`

Service Class

`using System.Collections.Generic;
using Northwind.Entities.Models;
using Northwind.Repository.Models;
using Northwind.Repository.Repositories;
using Repository.Pattern.Repositories;
using Service.Pattern;

namespace Northwind.Service
{
public class DynamicMenuService : Service, IDynamicMenuService
{
private readonly IRepositoryAsync _repository;
public DynamicMenuService(IRepositoryAsync repository) : base(repository)
{
_repository = repository;
}

    public IEnumerable<DynamicMenu> MenuByType(this IRepositoryAsync<DynamicMenu> repository
        , MenuCategory menuCategory, MenuType menuType)
    {
        return _repository.DynamicMenusByCategoryAndType(menuCategory, menuType);
    }
}

}`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.