Virtual Objects

Virtual Objects


Project maintained by AlienEngineer Hosted on GitHub Pages — Theme by mattgraham

Menu


Getting Started (Scaffolding)

This first version of the Scaffold only supports SqlServer.


// Creates all models based on the given data source.
Scaffold Models <SqlServer> <Database>

// Scaffold Switchs to change behavior
    -Repository                     (Creates a Repository layer of abstraction)
    -TableName <TableName>          (Create the entity model of a single table)
    -NoLazyLoad                     (Doesn't create virtual members)
    -ForceAnnotations               (Every field gets an annotation)
    -DefaultAttributes              (Use the default VirtualObjects.Mapping namespace)
    -DontConfig                     (Doesn't change the .Config connection string)
    -ModelFolder <FolderName>       (By default: Models)
    -RepositoryFolder <FolderName>  (By default: Repositories)
    -AnnotationsFolder <FolderName> (By default: Annotations)
    -ToFolder <FolderName>          (By default: Scaffolds into a folder)

What will be created and changed.


// Creates the RepositoryLayer
Scaffold Repository

// Scaffold Switchs to change behavior
    -ModelFolder <FolderName>       (By default: Models)
    -RepositoryFolder <FolderName>  (By default: Repositories)
    -AnnotationsFolder <FolderName> (By default: Annotations)
    -ToFolder <FolderName>          (By default: Scaffolds into a folder)

What will be created and changed.


// Sets the configuration string
Scaffold Config <ServerName> <DataBase>
    -ProviderName       (Use a different Provider)
    -ConfigName         (Change the configuration of the given name)

What will be created and changed.


// Creates the BusinessLayer
Scaffold Business <ModelType>
    -ModelFolder <FolderName>       (By default: Models)
    -BusinessFolder <FolderName>    (By default: Business)
    -ToFolder <FolderName>          (By default: Scaffolds into a folder)
    -NoDelete                       (Business doesnt support delete operations)
    -NoInsert                       (Business doesnt support insert operations)
    -NoUpdate                       (Business doesnt support update operations)
    -ReadOnly                       (Business for read operations only)

What will be created and changed.

Getting Started

Create a Model

public class Employee 
{
    public String EmployeeId { get; set; }
    public String LastName { get; set; }
    // Other fields ...
}

Config the Connection

  <connectionStrings>
    <clear/>
    <add name="YourMachineName" 
         providerName="System.Data.SqlClient" 
         connectionString="
               Data Source=.\instance;
               Initial Catalog=db;
               Integrated Security=true"/>
  </connectionStrings>

Use it!

   using (var session = new Session())
   {
      IQueryable<Employee> employees = session.GetAll<Employee>()
        .Where(e => e.BirthDate.Year > 1983);

      session.Insert(new Employee 
      {
         Name = "I'm the new guy!"
      });
   }

POCO classes (Plain Old CLR Object)

There's no need to derive our model types from any specific type. But they can... Our POCO classes should be defined with properties with R/W (get/set).

public int EmployeeId { get; set; }
public String LastName { get; set; }
public String FirstName { get; set; }
//...

In case we want lazy load of a foreign reference the property should be marked as Virtual (to enable interception). This is not a requirement, use it if you would like the ORM to load your references for you.

public virtual Employee ReportsTo { get; set; }

To map with the data source fields attributes can be used to add metadata to our poco classes. This is not a requirement.

This is fully configurable. To configure the way pocos are mapped, you must derive the type SessionConfiguration and override the method ConfigureMappingBuilder(IMappingBuilder builder). The final stage is to give the custom configuration to the Session. See above.

This configuration can be made so our pocos will be totally compatible with EntityFramework or other ORM frameworks/libraries.

class Configuration : SessionConfiguration
{    
    public override void ConfigureMappingBuilder(IMappingBuilder builder)
    {
        //
        // TableName getters
        //
        builder.EntityNameFromType(e => e.Name);
        builder.EntityNameFromAttribute<TableAttribute>(e => e.TableName);

        //
        // ColumnName getters
        //
        builder.ColumnNameFromProperty(e => e.Name);
        builder.ColumnNameFromAttribute<ColumnAttribute>(e => e.FieldName);

        // (e.g.) A key is a property that ends with 'Id'
        // builder.ColumnKeyFromProperty(e => e.Name.EndsWith("Id"));
        //
        builder.ColumnKeyFromAttribute<KeyAttribute>();
        builder.ColumnKeyFromAttribute<IdentityAttribute>();

        builder.ColumnIdentityFromAttribute<IdentityAttribute>();

        builder.ForeignKeyFromAttribute<AssociationAttribute>(e => e.OtherKey);
    }
}
using(var session = new Session(new Configuration())
{
   // Use the session with your custom configuration.
}

Crud Operations

   // Create
   Employee Sergio = session.Insert(new Employee 
   {
      FirstName = "Sérgio",
      LastName = "Ferreira",
      BirthDate = new DateTime(1983, 4, 16)
   });   

   // Read
   Employee employee = session.GetById(Employee { EmployeeId = 1 });

   // Update
   session.Update(employee);

   // Delete
   session.Delete(employee);

Linq Support

    IQueryable<T> query = Session.GetAll<T>();
    // Or
    IQueryable<T> query = Session.Query<T>();

All queries can be verified under "VirtualObjects.Tests.Queries" namespace.

Just to be clear, all Linq queries are translated into the proper SQL parameterized commands. The framework will only load what needs to be loaded from the data source.

To see the generated SQL just provide (to the session) a configuration instance that sets the Logger to Console.Out (or other) for debug purposes. In release versions your app should never have the logger setted. This could result in pour performance.

IQueryable Methods Supported

Supported Projections

    // On group joins (full entities and collection load)
    from o in Query<Orders>()
    join od in Query<OrderDetails>() on o equals od.Order into ods
    select new { Order = o, Details = ods }

    // On Joins (full entities load)
    from o in Query<Orders>()
    join od in Query<OrderDetails>() on o equals od.Order
    join e in Query<Employee>() on o.Employee equals e
    select new { Order = o, Detail = od, Employee = e }

    // Specific members projection
    from o in Query<Orders>()
    join od in Query<OrderDetails>() on o.Freight equals od.UnitPrice
    select new { o.OrderId, od.UnitPrice, o.ShipCity }

    Query<Employee>().Select(e => new { e.EmployeeId, e.LastName, e.FirstName })

    // Agregated Projection
    Query<Employee>().GroupBy(e => e.City)
    .Select(e => new
    {
        City = e.Key, 
        Min = e.Min(o => o.EmployeeId),
        Max = e.Max(o => o.EmployeeId),
        Sum = e.Sum(o => o.EmployeeId),
        Count = e.Count(),
        Average = e.Average(o => o.EmployeeId)
    })

    // Calculated Projection
    Query<Employee>().GroupBy(e => e.City)
    .Select(e => new
    {
        Average = e.Sum(o => o.EmployeeId) / (e.Count()*1.0) * 100.0
    })


Entity Mapping

To make entity mapping as fast as possible the framework creates an assembly specific for that entity. This assembly contains helper methods that are used by VirtualObjects to Create instances of that entity without using reflection, enables VO to Map properties given a datareader, and so on.

Data Type Mappings

Checkout the microsoft table at ADO.Net


Support or Contact

If you have any suggestions for this project or something is not working right please contact me at Alien.Software.Engineer@gmail.com or @AlienEngineer (github)

Get it as a NuGet Package here

   PM> Install-Package VirtualObjects