I have this code
var now = DateTime.UtcNow;
var currentRoleInsights = dbContext.DocumentInsights.Where(dr =>
dr.DocumentID == data.ID &&
insightIDsToDelete.Contains(dr.InsightID)).ToList();
foreach (var r in currentRoleInsights)
{
r.StatusID = StatusType.Deleted;
r.DeletedByAMSUserID = amsUserID;
r.DateDeleted = now;
}
Now if I query again using the code below:
var data = dbContext.DocumentInsights.Where(dr =>
dr.DocumentID == data.ID &&
insightIDsToDelete.Contains(dr.InsightID)).ToList();
will I get the data that is already updated with its status?
Note I did not yet call the dbContext.SaveChanges() and I don't want my code to look like this
var now = DateTime.UtcNow;
var currentRoleInsights = dbContext.DocumentInsights.Where(dr =>
dr.DocumentID == data.ID &&
insightIDsToDelete.Contains(dr.InsightID)).ToList();
foreach (var r in currentRoleInsights)
{
r.StatusID = StatusType.Deleted;
r.DeletedByAMSUserID = amsUserID;
r.DateDeleted = now;
}
dbContext.SaveChanges()
var data = dbContext.DocumentInsights.Where(dr =>
dr.DocumentID == data.ID &&
insightIDsToDelete.Contains(dr.InsightID)).ToList();
// modify data
will I get the data that is already updated with its status?
yes
// #nuget: EntityFramework
using System;
using System.Data.Entity;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
public class Program
{
public static void Main()
{
InsertData();
using (var context = new BookStore())
{
var authors = context.Authors.Include(a => a.Books).ToList();
DisplayData(authors);
foreach(var a in authors){
a.Books.ToList().ForEach(x=>x.Title = x.Title + " 2019");
}
Console.WriteLine();
authors = context.Authors.Include(a => a.Books).ToList();
DisplayData(authors);
}
}
public static void DisplayData(List<Author> list)
{
foreach(var author in list)
{
Console.WriteLine("Author Name: " + author.Name);
Console.WriteLine("\tBook List:");
foreach(var book in author.Books)
{
Console.WriteLine("\t\t" + book.Title);
}
}
}
public static void InsertData()
{
using (var context = new BookStore())
{
Author author1 = new Author()
{
Name = "Mark",
Books = new List<Book>
{
new Book() { Title = "Fundamentals of Computer Programming with C#"},
new Book() { Title = "Java: A Beginner's Guide"},
}
};
Author author2 = new Author()
{
Name = "Andy",
Books = new List<Book>
{
new Book() { Title = "SQL: The Ultimate Beginners Guide"}
}
};
Author author3 = new Author()
{
Name = "Johny",
Books = new List<Book>
{
new Book() { Title = "Learn VB.NET"},
new Book() { Title = "C# Fundamentals for Absolute Beginners"},
}
};
context.Authors.Add(author1);
context.Authors.Add(author2);
context.Authors.Add(author3);
context.SaveChanges();
}
}
public class BookStore : DbContext
{
public BookStore() : base(FiddleHelper.GetConnectionStringSqlServer())
{
}
public DbSet<Author> Authors { get; set; }
public DbSet<Book> Books { get; set; }
}
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public int AuthorId { get; set; }
[ForeignKey("AuthorId")]
public Author Author { get; set; }
}
public class Author
{
public int AuthorId { get; set; }
public string Name { get; set; }
public ICollection<Book> Books { get; set; }
}
}
copy and past the code above to https://dotnetfiddle.net/
Related
How can i write a compatible c# code for this?
I know i can do projection like this:
var projection = Builders<BsonDocument>.Projection.Include("title");
But no idea how to project the last name to get the author's last name after a lookup aggregation
db.books.aggregate(
[
{
$project: {
title: 1,
lastName: "$author.lastName",
}
}
]
)
Try this one
var project = new BsonDocument
{
{
"$project",
new BsonDocument
{
{"title", 1},
{"lastName", "$author.lastName"},
}
}
};
var pipelineLast = new[] { project };
var resultLast = db.books.Aggregate<BsonDocument>(pipelineLast);
var matchingExamples = await resultLast.ToListAsync();
foreach (var example in matchingExamples)
{
// Display the result
}
assuming your author entity is embedded inside the book entity, here's a strongly typed solution. if your author is a referenced entity, let me know and i'll update my answer.
using MongoDB.Entities;
using System;
using System.Linq;
namespace StackOverflow
{
public class Program
{
public class Book : Entity
{
public string Title { get; set; }
public Author Author { get; set; }
}
public class Author
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
private static void Main(string[] args)
{
new DB("test");
(new Book
{
Title = "a book title goes here",
Author = new Author
{
FirstName = "First Name",
LastName = "Last Name"
}
}).Save();
var res = DB.Queryable<Book>()
.Select(b => new
{
Title = b.Title,
LastName = b.Author.LastName
}).ToArray();
foreach (var b in res)
{
Console.WriteLine($"title: {b.Title} / lastname: {b.LastName}");
}
Console.Read();
}
}
}
the above code is using my library MongoDB.Entities for brevity. simply replace DB.Queryable<Book>() with collection.AsQueryable() for the official driver.
I got this code and it works without problems. But i sense there is much better way to do this.
namespace Repositories
{
public class AuthorRepository : IAuthorRepository
{
public List<Author> GetAllFromRepo()
{
using (AppContext myDB = new AppContext())
{
List<Author> authorsFromRepo = new List<Author>();
foreach (var item in myDB.Authors)
{
authorsFromRepo.Add(new Author()
{
Books = new List<Book>(),
ID = item.ID,
FirstName = item.FirstName,
LastName = item.LastName
});
}
return authorsFromRepo.ToList();
}
}
}
}
When i try something along the lines of this:
public List<Author> GetAllFromRepo()
{
using (AppContext myDB = new AppContext())
{
List<Author> authorsFromRepo = new List<Author>();
authorsFromRepo = myDB.Authors.ToList();
return authorsFromRepo;
}
}
I always get this error:
Value cannot be null.
Parameter name: source
Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: source
Source Error: Line 33: return authors.Select(x => new AuthorViewModel()
Any Help?
The model where the error takes me
namespace Services
{
public class AuthorService : IAuthorService
{
private readonly IAuthorRepository _AuthorRepository;
public AuthorService(IAuthorRepository authorRepository)
{
_AuthorRepository = authorRepository;
}
public List<AuthorViewModel> GetAll()
{
List<Author> authors = _AuthorRepository.GetAllFromRepo();
return authors.Select(x => new AuthorViewModel()
{
ID = x.ID,
FullName = $"{x.FirstName } {x.LastName} ",
Books = x.Books.Select(g => new BookViewModel()
{
ID = g.ID,
Name = g.Name
}).ToList()
}).ToList();
}
}
}
To add again, everything works fine if i use the first example of code.
When i try something shorter like
return myDB.Authors.ToList();
i get the error.
when i change to:
return authors.Select(x => new AuthorViewModel()
{
ID = x.ID,
FullName = $"{x.FirstName } {x.LastName} ",
Books = {}
}).ToList();
It works then... but this means it doesn't read the author books...
I had to change the model for Authors to
namespace Entities
{
public class Author
{
// this is what a had to add here
// From here
public Author()
{
Books = new List<Book>();
}
// to here
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Book> Books { get; set; }
}
}
So It wont give me any errors when x.Books is null.
I'm approaching to document database and I'm little bit confused how to map documents relationship, in a situation as follow
public class Person
{
public Person()
{
}
public int Id { get; set; }
public string Name { get;set;}
public string Surname { get; set; }
public DateTime? BirthDate { get; set; }
}
public class Car
{
public Car() { }
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set;}
}
A person has one or more cars for example in this way I can query the db as follow
public Car Get(int id)
{
Car car = null;
using (IDocumentSession session = store.OpenSession())
{
car = session.Include<Car, Person>(x => x.PersonId).Load<Car>(id);
bool isLoaded = session.Advanced.IsLoaded("people/" + car.PersonId); // true!
}
return car;
}
and it's everything ok, the client makes just one request, but if I have a person and I want to show all his cars how can I query the db to do just a request?
I think tha I must modify the model putting a List<int> Cars in Person for reference his cars.
Note that I don't want to embed Cars in the Person document because Cars can be referenced from others document.
Thanks.
You can do it like this:
using (IDocumentSession session = store.OpenSession())
{
var carsForOne = session.Query<Car>()
.Include(x=>x.PersonId)
.Where(x=>x.PersonId == "people/1")
.ToList();
var person = session.Load<Person>("people/1");
}
This make just a single db request.
You can index the Cars collection and load all the cars from the index.
The index would look like this:
public class CarIndex : AbstractIndexCreationTask<Car, CarView>
{
public CarIndex()
{
Map = cars => from car in cars
select new
{
car.Id,
car.Name,
car.PersonId,
};
}
}
The CarView class is identical to the Car class, but can be changed to better fit the indexing needs.
public class CarView
{
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set; }
}
You'll need to execute the index before being able to use it:
new CarIndex().Execute(store);
Loading the cars for a certain person would look like this:
using (IDocumentSession session = store.OpenSession())
{
session.Store(new Person { Id = 1, Name = "A", Surname = "A" });
session.Store(new Car { Id = 1, Name = "A", PersonId = 1 });
session.Store(new Car { Id = 2, Name = "B", PersonId = 1 });
session.Store(new Car { Id = 3, Name = "C", PersonId = 2 });
session.SaveChanges();
}
WaitForIndexing(store); // from RavenTestBase
using (IDocumentSession session = store.OpenSession())
{
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1);
Assert.Equal(2, resultsForId1.Count());
var resultsForId2 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 2);
Assert.Equal(1, resultsForId2.Count());
}
If you want to load the person and their cars in a single database request, use lazy loading:
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1).Lazily();
var person = session.Advanced.Lazily.Load<Person>(1);
var personValue = person.Value;
var resultsValue = resultsForId1.Value;
Complete test (needs xunit and RavenDB.Tests.Helpers nugets):
using Raven.Client;
using Raven.Client.Indexes;
using Raven.Tests.Helpers;
using System;
using System.Linq;
using Xunit;
namespace SO41547501Answer
{
public class SO41547501 : RavenTestBase
{
[Fact]
public void SO41547501Test()
{
using (var server = GetNewServer())
using (var store = NewRemoteDocumentStore(ravenDbServer: server))
{
new CarIndex().Execute(store);
using (IDocumentSession session = store.OpenSession())
{
session.Store(new Person { Id = 1, Name = "A", Surname = "A" });
session.Store(new Car { Id = 1, Name = "A", PersonId = 1 });
session.Store(new Car { Id = 2, Name = "B", PersonId = 1 });
session.Store(new Car { Id = 3, Name = "C", PersonId = 2 });
session.SaveChanges();
}
WaitForAllRequestsToComplete(server);
WaitForIndexing(store);
using (IDocumentSession session = store.OpenSession())
{
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1);
Assert.Equal(2, resultsForId1.Count());
var resultsForId2 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 2);
Assert.Equal(1, resultsForId2.Count());
}
using (IDocumentSession session = store.OpenSession())
{
server.Server.ResetNumberOfRequests();
var resultsForId1 = session
.Query<CarView, CarIndex>()
.ProjectFromIndexFieldsInto<CarView>()
.Where(x => x.PersonId == 1).Lazily();
var person = session.Advanced.Lazily.Load<Person>(1);
var personValue = person.Value;
var resultsValue = resultsForId1.Value;
Assert.Equal("A", personValue.Name); // person data loaded
Assert.Equal("A", resultsValue.First().Name); // cars data loaded
Assert.Equal(1, server.Server.NumberOfRequests); // only one request sent to the server
}
}
}
}
public class CarIndex : AbstractIndexCreationTask<Car, CarView>
{
public CarIndex()
{
Map = cars => from car in cars
select new
{
car.Id,
car.Name,
car.PersonId,
};
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime? BirthDate { get; set; }
}
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set; }
}
public class CarView
{
public int Id { get; set; }
public string Name { get; set; }
public int PersonId { get; set; }
}
}
I have the following model (comments define fields within given object)
public class ServiceModel
{
public List<ShippingRequest> ShippingRequest { get; set; }
public QuotesResult QuotesResult { get; set; }
}
public class ShippingRequest
{
public Address Address { get; private set; } // AddressId
public List<ShippingPackage> ShippingPackages { get; private set; }
}
public class ShippingPackage
{
public Package Package { get; private set; } // PackageId
public List<ShippingItem> ShippingItems { get; private set; } // IsSkipped
}
public class QuotesResult
{
public List<Quote> Quotes { get; set; } // PackageId, Cost
}
Suppose I have the following input, I need to get a list of AddressId's and corresponding Quotes that refer to that address (via PackageId). Quotes are already populated at this point.
Quote.PackageId = Package.PackageId
INPUT:
Suppose I have following input with three ShippingRequests
Address1 = {Package1, Package2, Package3}
Address2 = {Package5, Package8}
Address3 = {Package11, Package12}
To get the all the quotes for a given address I need to Join PackageId of "Package" with PackageId of Quote. That way I will know that this Quote belongs to this Address.
I've tried this but i get an error:
var addrQuotes = ServiceModel.ShippingRequest
.GroupJoin(ServiceModel.QuotesResult.Quotes, c1 => c1.ShippingPackages
.SelectMany(y => y.Package.Id), c2 => c2.PackageId, (c1, c2) =>
new {
c1.Address.Id,
Quotes = c2.Select(e =>
{
e.Price = c1.ShippingPackages.Any(
x => x.ShippingItems.All(y => y.IsSkipped))
? 0
: e.Price + ExtraCost;
e.Provider = GetName(e.Code);
return e;
})
}).OrderBy(q => q.Id);
One caviar to this is that I also need to check ShippingItems(s) that go in a Package. If ALL the ShippingItems within a ShippingPackage have boolean flag "IsSkipped" set to true, the Quote's Price should be set to 0, otherwise add Extra cost to Quote.Price.
OUTPUT:
Address1 = [Quote1, Quote20, Quote21, Quote50, ...]
Address2 = [Quote3, Quote100...]
Address3 = [Quote5, Quote33, Quote12]
Any help greatly appreciated.
I didn't do entire job but got something to compile and run without errors. This should get you pointed in right direction.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ServiceModel serviceModel = new ServiceModel()
{
ShippingRequest = new List<ShippingRequest>(){
new ShippingRequest() {
Address = "Address 1",
ShippingPackages = new List<ShippingPackage>() {
new ShippingPackage() { Package = "Package1"},
new ShippingPackage() { Package = "Package2"},
new ShippingPackage() { Package = "Package3"}
}
},
new ShippingRequest() {
Address = "Address 2",
ShippingPackages = new List<ShippingPackage>() {
new ShippingPackage() { Package = "Package5"},
new ShippingPackage() { Package = "Package8"},
}
},
new ShippingRequest() {
Address = "Address 3",
ShippingPackages = new List<ShippingPackage>() {
new ShippingPackage() { Package = "Package11"},
new ShippingPackage() { Package = "Package12"},
}
}
},
QuotesResult = new QuotesResult()
{
Quotes = new List<Quote>() {
new Quote() { Cost = 123, Id = "Package1"},
new Quote() { Cost = 123, Id = "Package2"},
new Quote() { Cost = 123, Id = "Package3"},
new Quote() { Cost = 123, Id = "Package11"},
new Quote() { Cost = 123, Id = "Package11"}
}
}
};
var addrQuotes = (from requests in serviceModel.ShippingRequest.Select(x => x.ShippingPackages.Select(y => new { address = x.Address, package = y})).SelectMany(z => z)
join quote in serviceModel.QuotesResult.Quotes
on requests.package.Package equals quote.Id
select new { quote = quote, package = requests }).ToList();
var results = addrQuotes.GroupBy(m => m.package.address)
.Select(n => new {
quotes = n.Select(c => c).Select(c1 => new {
address = c1.package.address,
quote = c1.quote
}).ToList()
}).ToList();
}
}
public class ServiceModel
{
public List<ShippingRequest> ShippingRequest { get; set; }
public QuotesResult QuotesResult { get; set; }
}
public class ShippingRequest
{
public string Address { get; set; } // AddressId
public List<ShippingPackage> ShippingPackages { get; set; }
}
public class ShippingPackage
{
public string Package { get; set; } // PackageId
public List<string> ShippingItems { get; set; } // IsSkipped
}
public class QuotesResult
{
public List<Quote> Quotes { get; set; } // PackageId, Cost
}
public class Quote
{
public string Id { get; set; }
public decimal Cost { get; set; }
}
}
I have a requirement to reflect on a object get all properties that are collections and
1)GetCount for each collection
2)GetTotalCount (allCollectionCount)
3)Call a method with this collection.
Below is what I have done so far with a made up noddy structure for semplicity.
I am stuck in how to call this method and how to get count for collection.
Any suggestions?
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace ConsoleApplication2
{
class Program
{
static void Main()
{
var request = GetDataRequest();
//Get all properties
List<PropertyInfo> propInfoList =
new List<PropertyInfo>(request.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public));
//Get collections only
var myClassCollections=propInfoList.Where(xxx => xxx.PropertyType.GetInterfaces().Any(x => x == typeof (IEnumerable))).ToList();
var totalCountForAllCollections=????
foreach (var col in myClassCollections)
{
//How do I call my Method DoSomething
// DoSomething<?>(col.?????)
}
}
public void DoSomething<T>(List<T> objectCollection)
{
//etc...
}
private static DataRequest GetDataRequest()
{
DataRequest request = new DataRequest();
request.Addresses.Add(new Address
{
Id = 1,
City = "London",
Postcode = "32131",
Street = "London Road"
});
request.Addresses.Add(new Address
{
Id = 2,
City = "NewYork",
Postcode = "3432",
Street = "NewYork Road"
});
request.Customers.Add(new Customer
{
Id = 1,
Name = "Jo",
Surname = "Bloggs",
});
request.Customers.Add(new Customer
{
Id = 1,
Name = "Jon",
Surname = "Bloggs2",
});
request.Customers.Add(new Customer
{
Id = 1,
Name = "Jonny",
Surname = "Bloggs3",
});
return request;
}
}
public class DataRequest
{
public DataRequest()
{
Customers = new List<Customer>();
Orders = new List<Order>();
Addresses = new List<Address>();
}
public List<Customer> Customers { get; set; }
public List<Order> Orders { get; set; }
public List<Address> Addresses { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
public class Order
{
public int Id { get; set; }
public string Name { get; set; }
public string OrderNo { get; set; }
}
public class Address
{
public int Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string Postcode { get; set; }
}
}
quick and dirty, here you go...
// ..
static class Program
{
static void Main()
{
var request = GetDataRequest();
//Get propertyValues for properties that are enumerable (i.e. lists,arrays etc)
var collectionProperties = request.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(propertInfo => propertInfo.PropertyType.GetInterfaces().Any(x => x == typeof(IEnumerable)))
.Select(p => p.GetValue(request, null))
.Cast<IEnumerable<object>>().ToList();
var totalCountForAllCollections = 0;
// iterate through the list of propertyValues
foreach (var collectionPropertyValue in collectionProperties)
{
totalCountForAllCollections += collectionPropertyValue.Count();
collectionPropertyValue.DoSomething();
}
System.Console.WriteLine("The total count for all collections is : {0}", totalCountForAllCollections);
System.Console.WriteLine("press any key to exit");
System.Console.ReadLine();
}
public static void DoSomething<T>(this IEnumerable<T> objectCollection)
{
//etc...
// N.B. you will have to use typeof(T) to implement logic specific to the type
// If the logic in this method is non-specific to the typeof(T) then Implement logic accordingly
System.Console.WriteLine("The type of the collection is: {0}", objectCollection.GetType());
System.Console.WriteLine("The count of items in this collection is:{0}", objectCollection.Count());
}
// ..
}
// ..