如何向域实体注入服务以及如何持久化实体

sha*_*328 3 c# domain-driven-design entity-framework dependency-injection clean-architecture

我正在创建一个旅游规划器。始终Tour在相同的坐标处开始和结束。开始和结束之间有Stops。停靠站包含旅行期间的具体Sight参观地点 + 参观时间。将景点添加到游览时,我插入一个新的停靠点,并根据停靠点之间的距离重新计算停靠点的到达时间。为此,我ITravelServiceprivate recalculateStopTimes(int fromIdx)方法中使用注入的实例。


我的问题如下:这一直有效,直到我想通过 ORM 将 Tour 对象保留在数据库中。由于私有 ITravelService,该功能将在检索后丢失。我考虑过通过 InsertSight/RemoveSight/RemoveStop 方法注入服务,但随后我需要用我创建的每个修改 Stops 的公共方法注入它。有没有更好的方法将这样的服务注入到实体中?或者我应该注射它吗?如果没有,我怎样才能获得相同的功能(重新计算停靠点)?

public interface ITravelService
{
        public TimeSpan CalculateTimeBetween(Coordinates from, Coordinates to);
}

public class Tour : ITour
    {
        private readonly List<Stop> _stops;
        private ITravelService _travelService;

        public IReadOnlyList<Stop> Stops { get { return _stops; } }
        public bool IsWithinLimit { get { return _stops.Last().TimeRange.From < (StartTime.TimeOfDay + Length); } }


        public Tour(DateTime startTime, TimeSpan length, Coordinates start, ITravelService travelService)
        {
            StartTime = startTime;
            Length = length;
            Stop firstStop = new Stop(start, new TimeRange(startTime.TimeOfDay, startTime.TimeOfDay));
            Stop lastStop = new Stop(start, new TimeRange(startTime.TimeOfDay, startTime.TimeOfDay));
            _stops = new List<Stop>() { firstStop, lastStop };
        }

        private void recalculateStopTimes(int fromIdx)
        {
            for (int i = fromIdx; i < _stops.Count - 1; i++)
            {
                Stop currentStop = _stops[i];
                Stop nextStop = _stops[i + 1];
                var travelTime = _travelService.CalculateTimeBetween(currentStop.Coordinates, nextStop.Coordinates);
                nextStop.Arrival = currentStop.TimeRange.To + travelTime;
            }
        }

        public void InsertSight(Sight sight, int index)
        {
            if (index == 0 || index == Stops.Count) throw new ArgumentOutOfRangeException("Cannot insert before first, or after last stop.");
            _stops.Insert(index, new SightStop(sight, StartTime.DayOfWeek));

            recalculateStopTimes(index - 1);
        }

        public void RemoveSight(Sight sightToRemove)
        {
            if (_stops.Count == 2) throw new ArgumentException("Sight is not in tour");
            int idx = 1;
            while (((_stops[idx] as SightStop).Sight != sightToRemove) && idx <= _stops.Count - 1)
            {
                idx++;
            }
            if (idx < _stops.Count)
            {
                RemoveStopAt(idx);
            }
            else
            {
                throw new ArgumentException("Sight is not in tour");
            }
        }

        public void RemoveStopAt(int index)
        {
            if (index > 0 && index < _stops.Count - 1)
            {
                _stops.RemoveAt(index);
                recalculateStopTimes(index - 1);
            }
            else
            {
                throw new ArgumentOutOfRangeException("Index was out of range");
            }
        }

        public IReadOnlyList<Sight> SightsInTour
        {
            get
            {
                return _stops.Where(stop => stop is SightStop).Select(x => (x as SightStop).Sight).ToList();
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

Ste*_*ven 7

如果您想坚持使用业务逻辑驻留在域实体内部的 DDD 方法,答案是应用方法注入

// ITravelService is injected into the public InsertSight method
public void InsertSight(Sight sight, int index, ITravelService travelService)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

方法注入注入是理想的,因为使用运行时数据和依赖项构造对象(使用构造函数注入)会导致各种麻烦。相反,使用方法注入时,使用类Tour使用依赖项,但从不将依赖项存储在任何字段中。

尖端: