Hi I'm trying to write a generic repository for delete operation , this is my Repository
public class Repository<T> : IRepository<T> where T : class, IAggregateRoot
{
private readonly DbSet<T> _entitySet;
private readonly StatosContext _statosContext;
public Repository(StatosContext statosContext)
{
_statosContext = statosContext;
_entitySet = statosContext.Set<T>();
}
public void Add(T entity)
{
_entitySet.Add(entity);
}
public void Delete(T entity)
{
_entitySet.Remove(entity);
}
}
when I call Delete via a service method like this
public void RemoveContact(ContactViewModel contactViewModel)
{
var categoryView = new ContactViewModel { ContactId = contactViewModel.ContactId };
var contact = categoryView.ConvertToContactModel();
_contactRepository.Delete(contact);
_contactRepository.SaveChanges();
}
it Doesn't work because it doesn't find the entity
how can I write Delete method in mt Generic repository ??
The issue is that your entity isnt attached yet.
Heres my generic repository, take a look how I do this
public void RemoveOnSave(T entity)
{
try
{
var e = m_Context.Entry(entity);
if (e.State == EntityState.Detached)
{
m_Context.Set<T>().Attach(entity);
e = m_Context.Entry(entity);
}
e.State = EntityState.Deleted;
}
catch (InvalidOperationException ex)
{
throw new RepositoryTrackingException(
"An attempt was made to delete an entity you are already modifying, this may happen if you are trying to update using the same repository instance in two place", ex);
}
}
https://github.com/lukemcgregor/StaticVoid.Repository/blob/master/StaticVoid.Repository.EntityFramework/DbContextRepositoryDataSource.cs
if you're working with disconnected entities and you're sure that the entity is not tracked by the context (you should), you can write this simple code.
public void Delete(T entity)
{
try
{
_entitySet.Attach(entity);
_entitySet.Remove(entity);
_statosContext.SaveChanges();
}
catch (OptimisticConcurrencyException e)
{
_statosContext.Refresh(RefreshMode.ClientWins,entity);
}
}
RefreshMode has 2 possible values: ClientWins and StoreWins. What value to choose depends on your strategy. Here I assume that you're implementing "Last Record Wins" strategy
Related
I have a problem when using microservice and Kafka
for example, I have Service A and Service B they communicate by Kafka and they share the same database inside the database and I have two entities A and B and they share a one-to-many relationship, when I update entity A in service A entity B gets updated/changed as wanted but when I view service B. I can't see the changes that happened in service A.
In my case example code :
here we are in service A:
KafkaService:
public synchronized void getDriverService(Long orderId, Double longitude, Double latitude) {
driverService.getDriver(orderId,longitude,latitude);
driverService.collectionOrder(orderId);
}
driverService:
public void getDriver(Long orderId, Double longitude, Double latitude) {
final Driver [] y={new Driver()};
ascOrderRepository.findById(orderId).ifPresentOrElse(x->{
List<DriverDTO> drivers = findAllCarNearMe(latitude, longitude);
if(drivers.isEmpty())
throwEmptyDriver();
AscOrderDTO orderDto = ascOrderMapper.toDto(x);
int check;
for (DriverDTO dr : drivers) {
check = checkDriver();
if (check < 8) {
log.debug("///////////////////////// driver accept" + dr.getId().toString());
dr.setStatus(UNAVAILABLE);
dr.updateTotalTrip();
Driver driver=driverMapper.toEntity(dr);
driver.addOrders(x);
y[0]=driverRepository.save(driver);
log.debug(dr.toString());
log.debug("/////////////////////////////////////driver accept here /////////////////////////////////////////");
break;
}
}
},this::throwOrder);
}
// find All Car near me
public List<DriverDTO> findAllCarNearMe(Double latitude, Double longitude) {
checkDistance(latitude,longitude);
Point point = createPoint(latitude, longitude);
List<Driver> driver = driverRepository.findNearById(point, 10);
return driverMapper.toDto(driver);
}
public void collectionOrder(Long orderId)
{
ascOrderRepository.findById(orderId).ifPresentOrElse(y->{
if(y.getDriver()!=null) { // here new updated and find this updated into service A
try {
driverProducer.driverCollectionOrder(y.getId());
} catch (Exception e) {
e.printStackTrace();
}
}
else
{
throwDriverNotFind();
}
},this::throwOrder);
}
This is Producer:
#Component public class DriverProducer {
public
DriverProducer(KafkaTemplate<String, String> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate; }
public void driverCollectionOrder(Long orderId) throws Exception{ ObjectMapper obj=new ObjectMapper();
kafkaTemplate.send("collecting",obj.writeValueAsString(orderId));
}
Service B:
This is Consumer:
#KafkaListener(topics = "collecting",groupId= groupId)
public void doneOrderStatus(String data) throws NumberFormatException, Exception {
try
{
log.debug("i am in done order status order consumer");
OrderEvent event=OrderEvent.TO_BE_COLLECTED;
orderService.changeStatus(event, Long.parseLong(data));
}
catch (Exception e)
{
throw new Exception(e.getMessage());
}
}
This Method Has my Error:
public void changeStatus(OrderEvent event, Long orderId) throws Exception {
try {
Optional<AscOrder> order=ascOrderRepository.findById(orderId);
if (!order.isPresent()) {
throw new BadRequestAlertException("cannot find Order", "Order entity", "Id invalid");
}
if(order.get().getDriver()!=null) { // cant find Change Here
log.debug("===============================================================================================");
log.debug(order.get().getDriver().toString());
log.debug("===============================================================================================");
}
log.debug("i am in changeStatus ");
stateMachineHandler.stateMachine(event, orderId);
stateMachineHandler.handling(orderId);
} catch (Exception e) {
throw new Exception(e.getMessage());
}
}
The problem may be about the separate ORM sessions held by the services.
To overcome this you may try to reload the entity. To do that,
1- wire the entity manager
#Autowired
EntityManager entityManager;
2- Decorate changeStatus function with #Transactional annotation, unless there is an active transaction already going on.
3- Refresh the order entity
entityManager.refresh(order)
Trying to model a system sending out notifications from a number of publishers using RX.
I have two custom interfaces ITopicObservable and ITopicObserver to model the fact that the implementing classes will have other properties and methods apart from the IObservable and IObserver interfaces.
The problem I have is that my thinking is I should be able to add a number of observables together, merge them together and subscribe to an observer to provide updates from all merged observables. However the code with "the issue" comment throws an invalid cast exception.
The use case is a number of independent sensors each monitoring a temperature in a box for example that aggregate all their reports to one temperature report which is then subscribed to by a temperature health monitor.
What am I missing here? Or is there a better way to implement the scenario using RX?
Code below
using System;
using System.Reactive.Linq;
using System.Collections.Generic;
namespace test
{
class MainClass
{
public static void Main (string[] args)
{
Console.WriteLine ("Hello World!");
var to = new TopicObserver ();
var s = new TopicObservable ("test");
var agg = new AggregatedTopicObservable ();
agg.Add (s);
agg.Subscribe (to);
}
}
public interface ITopicObservable<TType>:IObservable<TType>
{
string Name{get;}
}
public class TopicObservable:ITopicObservable<int>
{
public TopicObservable(string name)
{
Name = name;
}
#region IObservable implementation
public IDisposable Subscribe (IObserver<int> observer)
{
return null;
}
#endregion
#region ITopicObservable implementation
public string Name { get;private set;}
#endregion
}
public class AggregatedTopicObservable:ITopicObservable<int>
{
List<TopicObservable> _topics;
private ITopicObservable<int> _observable;
private IDisposable _disposable;
public AggregatedTopicObservable()
{
_topics = new List<TopicObservable>();
}
public void Add(ITopicObservable<int> observable)
{
_topics.Add ((TopicObservable)observable);
}
#region IObservable implementation
public IDisposable Subscribe (IObserver<int> observer)
{
_observable = (ITopicObservable<int>)_topics.Merge ();
_disposable = _observable.Subscribe(observer);
return _disposable;
}
#endregion
#region ITopicObservable implementation
public string Name { get;private set;}
#endregion
}
public interface ITopicObserver<TType>:IObserver<TType>
{
string Name{get;}
}
public class TopicObserver:ITopicObserver<int>
{
#region IObserver implementation
public void OnNext (int value)
{
Console.WriteLine ("next {0}", value);
}
public void OnError (Exception error)
{
Console.WriteLine ("error {0}", error.Message);
}
public void OnCompleted ()
{
Console.WriteLine ("finished");
}
#endregion
#region ITopicObserver implementation
public string Name { get;private set;}
#endregion
}
}
My first thought, is that you shouldn't implement IObservable<T>, you should compose it by exposing it as a property or the result of a method.
Second thought is that there are operators in Rx that excel at merging/aggregating multiple sequences together.
You should favor using those.
Third, which is similar to the first, you generally don't implement IObserver<T>, you just subscribe to the observable sequence and provide delegates for each call back (OnNext, OnError and OnComplete)
So your code basically is reduced to
Console.WriteLine("Hello World!");
var topic1 = TopicListener("test1");
var topic2 = TopicListener("test2");
topic1.Merge(topic2)
.Subscribe(
val => { Console.WriteLine("One of the topics published this value {0}", val);},
ex => { Console.WriteLine("One of the topics errored. Now the whole sequence is dead {0}", ex);},
() => {Console.WriteLine("All topics have completed.");});
Where TopicListener(string) is just a method that returns IObservable<T>.
The implementation of the TopicListener(string) method would most probably use Observable.Create.
It may help to see examples of mapping Rx over a Topic based messaging system.
There is an example of how you can layer Rx over TibRv topics here https://github.com/LeeCampbell/RxCookbook/blob/master/IO/Comms/TibRvSample.linq
The signature of the .Merge(...) operator that you're using is:
IObservable<TSource> Merge<TSource>(this IEnumerable<IObservable<TSource>> sources)
The actual type returned by this .Merge() is:
System.Reactive.Linq.ObservableImpl.Merge`1[System.Int32]
...so it should be fairly clear that calling (ITopicObservable<int>)_topics.Merge(); would fail.
Lee's advice not to implement either of IObservable<> or IObserver<> is the correct one. It leads to errors like the one above.
If you had to do something like this, I would do it this way:
public interface ITopic
{
string Name { get; }
}
public interface ITopicObservable<TType> : ITopic, IObservable<TType>
{ }
public interface ITopicSubject<TType> : ISubject<TType>, ITopicObservable<TType>
{ }
public interface ITopicObserver<TType> : ITopic, IObserver<TType>
{ }
public class Topic
{
public string Name { get; private set; }
public Topic(string name)
{
this.Name = name;
}
}
public class TopicSubject : Topic, ITopicSubject<int>
{
private Subject<int> _subject = new Subject<int>();
public TopicSubject(string name)
: base(name)
{ }
public IDisposable Subscribe(IObserver<int> observer)
{
return _subject.Subscribe(observer);
}
public void OnNext(int value)
{
_subject.OnNext(value);
}
public void OnError(Exception error)
{
_subject.OnError(error);
}
public void OnCompleted()
{
_subject.OnCompleted();
}
}
public class AggregatedTopicObservable : Topic, ITopicObservable<int>
{
List<ITopicObservable<int>> _topics = new List<ITopicObservable<int>>();
public AggregatedTopicObservable(string name)
: base(name)
{ }
public void Add(ITopicObservable<int> observable)
{
_topics.Add(observable);
}
public IDisposable Subscribe(IObserver<int> observer)
{
return _topics.Merge().Subscribe(observer);
}
}
public class TopicObserver : Topic, ITopicObserver<int>
{
private IObserver<int> _observer;
public TopicObserver(string name)
: base(name)
{
_observer =
Observer
.Create<int>(
value => Console.WriteLine("next {0}", value),
error => Console.WriteLine("error {0}", error.Message),
() => Console.WriteLine("finished"));
}
public void OnNext(int value)
{
_observer.OnNext(value);
}
public void OnError(Exception error)
{
_observer.OnError(error);
}
public void OnCompleted()
{
_observer.OnCompleted();
}
}
And run it with:
var to = new TopicObserver("watching");
var ts1 = new TopicSubject("topic 1");
var ts2 = new TopicSubject("topic 2");
var agg = new AggregatedTopicObservable("agg");
agg.Add(ts1);
agg.Add(ts2);
agg.Subscribe(to);
ts1.OnNext(42);
ts1.OnCompleted();
ts2.OnNext(1);
ts2.OnCompleted();
Which gives:
next 42
next 1
finished
But apart from being able to give everything a name (which I'm not sure how it helps) you could always do this:
var to =
Observer
.Create<int>(
value => Console.WriteLine("next {0}", value),
error => Console.WriteLine("error {0}", error.Message),
() => Console.WriteLine("finished"));
var ts1 = new Subject<int>();
var ts2 = new Subject<int>();
var agg = new [] { ts1, ts2 }.Merge();
agg.Subscribe(to);
ts1.OnNext(42);
ts1.OnCompleted();
ts2.OnNext(1);
ts2.OnCompleted();
Same output with no interfaces and classes.
There's even a more interesting way. Try this:
var to =
Observer
.Create<int>(
value => Console.WriteLine("next {0}", value),
error => Console.WriteLine("error {0}", error.Message),
() => Console.WriteLine("finished"));
var agg = new Subject<IObservable<int>>();
agg.Merge().Subscribe(to);
var ts1 = new Subject<int>();
var ts2 = new Subject<int>();
agg.OnNext(ts1);
agg.OnNext(ts2);
ts1.OnNext(42);
ts1.OnCompleted();
ts2.OnNext(1);
ts2.OnCompleted();
var ts3 = new Subject<int>();
agg.OnNext(ts3);
ts3.OnNext(99);
ts3.OnCompleted();
This produces:
next 42
next 1
next 99
It allows you to add new source observables after the merge!
After reading, this question. I figured I need to look over my structure to avoid redundant code.
My current structure is Controller -> Repository -> IRepository.
The repository looks like this:
public class UserRepository : IUserRepository, IDisposable
{
private StudentSchedulingEntities _context;
public UserRepository(StudentSchedulingEntities context)
{
if (context == null)
throw new ArgumentNullException("context");
_context = context;
}
public IEnumerable<User> GetUsers()
{
return _context.Users.ToList();
}
public User GetUserByID(int id)
{
return _context.Users.Find(id);
}
public void InsertStudent(User user)
{
_context.Users.Add(user);
}
public void DeleteStudent(int userID)
{
User usr = _context.Users.Find(userID);
_context.Users.Remove(usr);
}
public void UpdateStudent(User user)
{
_context.Entry(user).State = EntityState.Modified;
}
public void Save() {
_context.SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_context != null)
{
_context.Dispose();
_context = null;
}
}
}
}
My IRepository looks like this:
public interface IUserRepository : IDisposable
{
IEnumerable<User> GetUsers();
User GetUserByID(int userID);
void InsertStudent(User user);
void DeleteStudent(int userID);
void UpdateStudent(User user);
void Save();
}
I want to avoid doing this again in the service layer. Do I need the Repository Class or should I just implement the Service Layer in replacement of the Repository?
Your service layer won't need any repository implementations, it will simply use a repository to lookup a user, add/edit/delete a user, etc.
Now, if I can offer a bit of opinion, I'd recommend going with a generic repository. That way, if you need to make new repositories it is really simple. We use nopCommerce, and they use the following code:
public partial interface IRepository<T> where T : BaseEntity
{
T GetById(object id);
void Insert(T entity);
void Update(T entity);
void Delete(T entity);
IQueryable<T> Table { get; }
}
And since it use Entity Framework, this is the implementation:
/// <summary>
/// Entity Framework repository
/// </summary>
public partial class EfRepository<T> : IRepository<T> where T : BaseEntity
{
private readonly IDbContext _context;
private IDbSet<T> _entities;
/// <summary>
/// Ctor
/// </summary>
/// <param name="context">Object context</param>
public EfRepository(IDbContext context)
{
this._context = context;
}
public T GetById(object id)
{
return this.Entities.Find(id);
}
public void Insert(T entity)
{
try
{
if (entity == null)
throw new ArgumentNullException("entity");
this.Entities.Add(entity);
this._context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
var msg = string.Empty;
foreach (var validationErrors in dbEx.EntityValidationErrors)
foreach (var validationError in validationErrors.ValidationErrors)
msg += string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine;
var fail = new Exception(msg, dbEx);
//Debug.WriteLine(fail.Message, fail);
throw fail;
}
}
public void Update(T entity)
{
try
{
if (entity == null)
throw new ArgumentNullException("entity");
this._context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
var msg = string.Empty;
foreach (var validationErrors in dbEx.EntityValidationErrors)
foreach (var validationError in validationErrors.ValidationErrors)
msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
var fail = new Exception(msg, dbEx);
//Debug.WriteLine(fail.Message, fail);
throw fail;
}
}
public void Delete(T entity)
{
try
{
if (entity == null)
throw new ArgumentNullException("entity");
this.Entities.Remove(entity);
this._context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
var msg = string.Empty;
foreach (var validationErrors in dbEx.EntityValidationErrors)
foreach (var validationError in validationErrors.ValidationErrors)
msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
var fail = new Exception(msg, dbEx);
//Debug.WriteLine(fail.Message, fail);
throw fail;
}
}
public virtual IQueryable<T> Table
{
get
{
return this.Entities;
}
}
private IDbSet<T> Entities
{
get
{
if (_entities == null)
_entities = _context.Set<T>();
return _entities;
}
}
//TODO implement IDisposable interface
}
Now it would be as simple as IRepository<User> or IRepository<Whatever>.
Definitely no to redundant code :-) When you say:
My current structure is Controller -> Repository ->
Is Controller inheriting from Repository? You don't want that either. The repository layer typically interfaces to storage (XML, database, file system, etc) and maps to repository friendly classes. Another layer manages the mapping of the repository layer to your native business/service classes.
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
I get this error, but I am the only person using the database. I am using Entity Framework 4.1 with DBContext.
I am updating my records and SQL Profiler is showing a queue being sent in. What could be the causes of this issue?
The post:
[HttpPost]
public ActionResult EditUser(User user)
{
uow.UserRepository.Update(user);
uow.Save();
return RedirectToAction("Index", "User");
}
On this call:
public void Save()
{
_context.SaveChanges();
}
This is how it is attached
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
Update:
public class UnitOfWork : IDisposable
{
private StudentSchedulingEntities _context = new StudentSchedulingEntities();
private GenericRepository<User> userRepository;
private GenericRepository<UserRole> userRoleRepository;
private bool disposed = false;
public GenericRepository<User> UserRepository
{
get
{
if (this.userRepository == null)
{
this.userRepository = new GenericRepository<User>(_context);
}
return userRepository;
}
}
public GenericRepository<UserRole> UserRoleRepository
{
get
{
if (this.userRoleRepository == null)
{
this.userRoleRepository = new GenericRepository<UserRole>(_context);
}
return userRoleRepository;
}
}
public void Save()
{
_context.SaveChanges();
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
_context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
The ID field must be there in order to update the information properly. Otherwise, it will be throw a null. (I forgot to put the hidden field for ID in)
I have a springframework application in which I would like to add a transaction listener to a transaction which is currently in progress. The motivation is to trigger a post commit action which notifies downstream systems. I am using #Transactional to wrap a transaction around some service method -- which is where I want to create/register the post transaction listener. I want to do something "like" the following.
public class MyService {
#Transaction
public void doIt() {
modifyObjects();
// something like this
getTransactionManager().registerPostCommitAction(new
TransactionSynchronizationAdapter() {
public void afterCommit() {
notifyDownstream();
}
});
}
}
Spring has a TransactionSynchronization interface and adapter class which seems exactly what I want; however it is not immediately clear how to register one dynamically with either the current transaction, or the transaction manager. I would rather not subclass JtaTransactionManager if I can avoid it.
Q: Has anyone done this before.
Q: what is the simplest way to register my adapter?
Actually it was not as hard as I thought; spring has a static helper class that puts the 'right' stuff into the thread context.
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronizationAdapter() {
#Override
public void afterCommit() {
s_logger.info("TRANSACTION COMPLETE!!!");
}
}
);
you could use an aspect to match transactional methods aspect in your service to accomplish this:
#Aspect
public class AfterReturningExample {
#AfterReturning("execution(* com.mypackage.MyService.*(..))")
public void afterReturning() {
// ...
}
}
Here is a more complete solution I did for a similar problem that with wanting my messages sent after transactions are committed (I could have used RabbitMQ TX but they are rather slow).
public class MessageBusUtils {
public static Optional<MessageBusResourceHolder> getTransactionalResourceHolder(TxMessageBus messageBus) {
if ( ! TransactionSynchronizationManager.isActualTransactionActive()) {
return Optional.absent();
}
MessageBusResourceHolder o = (MessageBusResourceHolder) TransactionSynchronizationManager.getResource(messageBus);
if (o != null) return Optional.of(o);
o = new MessageBusResourceHolder();
TransactionSynchronizationManager.bindResource(messageBus, o);
o.setSynchronizedWithTransaction(true);
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(new MessageBusResourceSynchronization(o, messageBus));
}
return Optional.of(o);
}
private static class MessageBusResourceSynchronization extends ResourceHolderSynchronization<MessageBusResourceHolder, TxMessageBus> {
private final TxMessageBus messageBus;
private final MessageBusResourceHolder holder;
public MessageBusResourceSynchronization(MessageBusResourceHolder resourceHolder, TxMessageBus resourceKey) {
super(resourceHolder, resourceKey);
this.messageBus = resourceKey;
this.holder = resourceHolder;
}
#Override
protected void cleanupResource(MessageBusResourceHolder resourceHolder, TxMessageBus resourceKey,
boolean committed) {
resourceHolder.getPendingMessages().clear();
}
#Override
public void afterCompletion(int status) {
if (status == TransactionSynchronization.STATUS_COMMITTED) {
for (Object o : holder.getPendingMessages()) {
messageBus.post(o, false);
}
}
else {
holder.getPendingMessages().clear();
}
super.afterCompletion(status);
}
}
}
public class MessageBusResourceHolder extends ResourceHolderSupport {
private List<Object> pendingMessages = Lists.newArrayList();
public void addMessage(Object message) {
pendingMessages.add(message);
}
protected List<Object> getPendingMessages() {
return pendingMessages;
}
}
Now in your class where you actually send the message you will do
#Override
public void postAfterCommit(Object o) {
Optional<MessageBusResourceHolder> holder = MessageBusTxUtils.getTransactionalResourceHolder(this);
if (holder.isPresent()) {
holder.get().addMessage(o);
}
else {
post(o, false);
}
}
Sorry for the long winded coding samples but hopefully that will show someone how to do something after a commit.
Does it make sense to override the transaction manager on the commit and rollback methods, calling super.commit() right at the beginning.